> ## Documentation Index
> Fetch the complete documentation index at: https://raindrop.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Vertex AI (Beta)

> Automatic tracing for Google Vertex AI / Gen AI applications with Raindrop

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @raindrop-ai/vertex-ai @google/genai
  ```

  ```bash pip theme={null}
  pip install raindrop-vertex-ai google-genai
  ```
</CodeGroup>

## Quick Start

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { createRaindropVertexAI } from "@raindrop-ai/vertex-ai";
  import { GoogleGenAI } from "@google/genai";

  const raindrop = createRaindropVertexAI({
    writeKey: "your-write-key",
    userId: "user-123",
  });

  const client = new GoogleGenAI({ apiKey: "..." });
  const wrapped = raindrop.wrap(client);

  const response = await wrapped.models.generateContent({
    model: "gemini-2.0-flash",
    contents: "What is the capital of France?",
  });

  console.log(response.text);
  await raindrop.shutdown();
  ```

  ```python Python theme={null}
  from raindrop_vertex_ai import create_raindrop_vertex_ai
  from google import genai

  raindrop = create_raindrop_vertex_ai(api_key="your-write-key", user_id="user-123")
  client = genai.Client(api_key="...")
  wrapped = raindrop.wrap(client)

  response = wrapped.models.generate_content(
      model="gemini-2.0-flash",
      contents="What is the capital of France?",
  )

  print(response.text)
  raindrop.shutdown()
  ```
</CodeGroup>

## What Gets Traced

* **generateContent** — input text (user messages only), output, model, token usage (promptTokenCount/candidatesTokenCount)
* **Cached tokens** — `cached_content_token_count` from usage metadata → `ai.usage.cached_tokens`
* **Thinking tokens** — `thoughts_token_count` from usage metadata (Gemini 2.5) → `ai.usage.thoughts_tokens`
* **Finish reason** — `candidate.finish_reason` (STOP, MAX\_TOKENS, SAFETY, RECITATION) → `vertex_ai.finish_reason`
* **Errors** — captured with error status, re-thrown to caller

## Configuration

<CodeGroup>
  ```typescript TypeScript theme={null}
  const raindrop = createRaindropVertexAI({
    writeKey: "your-write-key",       // Optional: omit to disable telemetry
    endpoint: "...",          // Optional: custom Raindrop API endpoint
    userId: "user-123",      // Optional: associate events with a user
    convoId: "convo-456",    // Optional: conversation/thread ID
    projectId: "support-prod", // Optional: route events to a specific project (slug)
    debug: false,             // Optional: enable verbose logging
  });
  ```

  ```python Python theme={null}
  raindrop = create_raindrop_vertex_ai(
      api_key="your-write-key",           # Optional: your Raindrop API key
      user_id="user-123",                 # Optional: associate events with a user
      convo_id="convo-456",               # Optional: conversation/thread ID
      project_id="support-prod",          # Optional: route events to a specific project (slug)
      tracing_enabled=True,               # Optional: enable Raindrop tracing (default: True)
      bypass_otel_for_tools=True,         # Optional: bypass OTEL for tools (default: True)
      debug=False,                        # Optional: enable verbose logging
  )
  ```
</CodeGroup>

## Projects

Route events to a specific [project](/platform/projects) by passing its slug as `projectId` (`project_id` in Python):

<CodeGroup>
  ```typescript TypeScript theme={null}
  const raindrop = createRaindropVertexAI({
    writeKey: "your-write-key",
    projectId: "support-prod",
  });
  ```

  ```python Python theme={null}
  raindrop = create_raindrop_vertex_ai(
      api_key="your-write-key",
      project_id="support-prod",
  )
  ```
</CodeGroup>

This sets the `X-Raindrop-Project-Id` header on every event. Omit it (or pass `"default"`) to use your org's default **Production** project, which is the existing behavior. Single-project orgs need nothing new.

### Multiple projects in one process

Available in `raindrop-ai>=0.0.56`. When one service wraps several Vertex AI
clients that should report to **different** projects, create one
`RaindropVertexAI` wrapper per project. Each wrapper owns its own
`raindrop.Raindrop` client, so the two route independently — there is no shared
module-level state:

```python theme={null}
from raindrop_vertex_ai import create_raindrop_vertex_ai

# One long-lived wrapper per project, created at startup and reused.
rd_support = create_raindrop_vertex_ai(api_key="your-write-key", project_id="support-prod")
rd_billing = create_raindrop_vertex_ai(api_key="your-write-key", project_id="billing-prod")

support_client = rd_support.wrap(support_client)   # -> support-prod
billing_client = rd_billing.wrap(billing_client)   # -> billing-prod

rd_support.flush()
rd_billing.flush()
```

Each wrapper owns its configuration and delivery pipeline, so clients handled by
different wrappers route independently. To share a single client across wrappers
(or with the module-level API), construct a `raindrop.Raindrop` yourself and
pass it via `client=`:

```python theme={null}
from raindrop import Raindrop

client = Raindrop(api_key="your-write-key", project_id="support-prod")
raindrop = create_raindrop_vertex_ai(client=client)
```

## identify()

<CodeGroup>
  ```typescript TypeScript theme={null}
  raindrop.users.identify({ userId: "user-123", traits: { plan: "pro", org: "acme" } });
  ```

  ```python Python theme={null}
  raindrop.identify(user_id="user-123", traits={"plan": "pro", "org": "acme"})
  ```
</CodeGroup>

## track\_signal()

<CodeGroup>
  ```typescript TypeScript theme={null}
  raindrop.signals.track({
    eventId: "evt-abc",
    name: "thumbs_up",
    type: "feedback",
    sentiment: "POSITIVE",
    comment: "Great response!",
  });
  ```

  ```python Python theme={null}
  raindrop.track_signal(
      event_id="evt-abc",
      name="thumbs_up",
      signal_type="feedback",
      sentiment="POSITIVE",
      comment="Great response!",
  )
  ```
</CodeGroup>

## Flushing and Shutdown

<CodeGroup>
  ```typescript TypeScript theme={null}
  await raindrop.flush();     // flush pending data
  await raindrop.shutdown();  // flush + release resources
  ```

  ```python Python theme={null}
  raindrop.flush()     # flush pending data
  raindrop.shutdown()  # flush + release resources
  ```
</CodeGroup>

## finish\_reason Tracking

The Python wrapper captures `candidate.finish_reason` from Vertex AI responses and maps it to `vertex_ai.finish_reason` in event properties. Possible values: `STOP`, `MAX_TOKENS`, `SAFETY`, `RECITATION`.

## Token Tracking

The following token usage fields are captured from `usage_metadata`:

| Field                        | Property Key                 | Description                  |
| ---------------------------- | ---------------------------- | ---------------------------- |
| `prompt_token_count`         | `ai.usage.prompt_tokens`     | Input tokens                 |
| `candidates_token_count`     | `ai.usage.completion_tokens` | Output tokens                |
| `cached_content_token_count` | `ai.usage.cached_tokens`     | Cached input tokens          |
| `thoughts_token_count`       | `ai.usage.thoughts_tokens`   | Thinking tokens (Gemini 2.5) |

## Factory Function

A `create_raindrop_vertex_ai()` factory is also available:

```python theme={null}
from raindrop_vertex_ai import create_raindrop_vertex_ai

raindrop = create_raindrop_vertex_ai(api_key="rk_...", user_id="user-123")
```

## Known Limitations

* **Python SDK**: No `events.*` API — use `raindrop.analytics` directly. `identify()` and `track_signal()` are available on the wrapper instance.
* **Streaming**: `generateContentStream()` is not instrumented. Only `generateContent()` is traced.
