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

# Google Gemini

> Wrap the Google Gen AI client to meter and gate Gemini calls, one-shot and chat, streaming included.

## Set up

Wrap an instance of `GoogleGenAI` from `@google/genai`, Google's Gen AI SDK. The SDK recognizes it automatically.

```typescript theme={null}
import { GoogleGenAI } from '@google/genai';

const ai = stigg.wrap(new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY }));

await ai.models.generateContent({
  model: 'gemini-3.8-flash',
  contents: 'Summarize this ticket',
  stiggContext: { customerId: 'customer-acme', entitlement: { currencyId: 'credits' } },
});
```

Both `models.generateContent` and `models.generateContentStream` are covered. A streamed call is reported once, when the stream finishes.

### Chats: wrap each chat as well

Gemini has two ways to call a model: one-shot calls through `ai.models`, and conversations through `ai.chats`. A chat keeps its own reference to the original, unwrapped client, so calls made through a chat are **not** metered by wrapping the client alone. Wrap each chat you create too:

```typescript theme={null}
const chat = stigg.wrap(ai.chats.create({ model: 'gemini-3.8-flash' }));

await chat.sendMessage({
  message: 'What changed since yesterday?',
  stiggContext: { customerId: 'customer-acme', entitlement: { currencyId: 'credits' } },
});
```

Both `sendMessage` and `sendMessageStream` are covered. Nothing is counted twice if you wrap both the client and a chat, because a chat never goes through the wrapped client.

### Automatic function calling: stream the call

When you give Gemini a function it can call, Google's SDK can run the tool loop for you: one `generateContent` call can make up to ten model calls, and returns only the last response. Without streaming, the usage of the earlier calls is not in that response, so it cannot be reported. The SDK reports what it can see, tags the event with `gemini_afc_rounds`, and reports the shortfall to `onError`.

To meter every round, either stream the call, or set `automaticFunctionCalling: { disable: true }` and run the loop yourself, so each model call goes through the wrapped client. See Google's [function calling guide](https://ai.google.dev/gemini-api/docs/function-calling).

### Requested usage

To check each call against its output limit instead of a [requested usage](/documentation/ai-agents/llm-wrappers/gating#requested-usage) of 1, use the opt-in `estimateFromMaxOutputTokens(tokensPerUnit)` estimate. It reads `config.maxOutputTokens` from the call.

## What is reported

Every Gemini response includes a `usageMetadata` object: the number of tokens the call used, split into the prompt, the response, tokens served from the cache, thinking tokens and tool-use prompt tokens, with a total. The wrapper reads these and reports them to Stigg under Gemini's own names. For details on each field, see Google's [`UsageMetadata` reference](https://ai.google.dev/api/generate-content#UsageMetadata) and [token counting guide](https://ai.google.dev/gemini-api/docs/tokens).

| Method | Event name |
| - | - |
| `models.generateContent` | `gemini.models.generateContent` |
| `models.generateContentStream` | `gemini.models.generateContentStream` |
| `chats.sendMessage` (a wrapped chat) | `gemini.chats.sendMessage` |
| `chats.sendMessageStream` (a wrapped chat) | `gemini.chats.sendMessageStream` |

| Metric | What it counts |
| - | - |
| `promptTokenCount` | Prompt tokens, **including** cached tokens |
| `candidatesTokenCount` | Response tokens, **not including** thinking tokens |
| `cachedContentTokenCount` | Prompt tokens served from the [context cache](https://ai.google.dev/gemini-api/docs/caching) |
| `thoughtsTokenCount` | Thinking tokens of a reasoning model, billed as output |
| `toolUsePromptTokenCount` | Prompt tokens from tool use |
| `totalTokenCount` | All of the above, as Gemini reports it |

<Warning>
  Gemini's counters overlap in both directions. `promptTokenCount` already includes `cachedContentTokenCount`, so pricing both bills cached tokens twice. `thoughtsTokenCount` and `toolUsePromptTokenCount` are **not** included in the prompt or response counts, so if you leave them out of your pricing, a reasoning model's thinking tokens are free. `promptTokenCount`, `candidatesTokenCount`, `thoughtsTokenCount` and `toolUsePromptTokenCount` add up to `totalTokenCount`. Price the total, or the parts, but never both.
</Warning>

To avoid working this out, use the [normalized metrics](/documentation/ai-agents/llm-wrappers/metering#normalized-metrics-across-vendors). They count Gemini's cached tokens once, and its thinking and tool-use tokens as output and input.

Every usage field Gemini returns is also included, with a `raw.` prefix. See [How usage is reported](/documentation/ai-agents/llm-wrappers/supported-providers#how-usage-is-reported).

## Not covered

Only text generation is metered. Embeddings (`models.embedContent`), image and video generation, `countTokens`, batch jobs, cache management and the Live API are billable but count in different units, so they are passed through without checks or reporting. To meter one of them, write [your own recipe](/documentation/ai-agents/llm-wrappers/providers/custom).


## Related topics

- [Supported providers and gateways](/documentation/ai-agents/llm-wrappers/supported-providers.md)
- [JavaScript](/api-and-sdks/changelog/agent-sdk/javascript.md)
- [Google Sheets](/documentation/importing-and-exporting-data/export/google-sheets.md)
- [Google Cloud Storage](/documentation/importing-and-exporting-data/export/gcs.md)
- [Agent SDK](/api-and-sdks/references/sdk/backend/graphql/agent-sdk.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.