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

# Gemini

> Trace Gemini SDK calls, run evals, and use Gemini models in Braintrust

If you are a coding agent, prefer the Braintrust [`bt` CLI](/docs/reference/cli/quickstart) for repeatable, scriptable work: running evals, instrumenting code, querying logs, syncing data, managing functions, and configuring coding agents. Use the MCP server for reasoning over Braintrust data in conversation, such as ad-hoc lookups and exploration from your IDE.

[Google Gemini](https://ai.google.dev/gemini-api/docs) is Google's family of multimodal models, including Gemini 3.1 Pro and Gemini 3.6 Flash. Braintrust traces Gemini requests across text, streaming, structured outputs, function calling, and multimodal generation, lets you run experiments against Gemini models, and routes to them from the playground.

<View title="TypeScript" icon="https://img.logo.dev/typescriptlang.org?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  Trace Gemini calls from your TypeScript application, then run experiments against Gemini models.

  <h2 id="tracing-typescript">
    Tracing
  </h2>

  Trace Gemini calls to Braintrust with the native Google GenAI SDK, or route them through the Braintrust gateway.

  <h3 id="setup-typescript">
    Setup
  </h3>

  Install the Braintrust and Google GenAI SDKs, then set your API keys.

  <Steps>
    <Step title="Install packages">
      <CodeGroup>
        ```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        pnpm add braintrust @google/genai
        ```

        ```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
        npm install braintrust @google/genai
        ```
      </CodeGroup>
    </Step>

    <Step title="Set environment variables">
      ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      GEMINI_API_KEY=<your-gemini-api-key>
      BRAINTRUST_API_KEY=<your-braintrust-api-key>

      # For organizations on the EU data plane, use https://api-eu.braintrust.dev
      # For self-hosted deployments, use your data plane URL
      # BRAINTRUST_API_URL=<your-braintrust-api-url-here>
      ```
    </Step>
  </Steps>

  <h3 id="auto-instrumentation-typescript">
    Auto-instrumentation
  </h3>

  To trace Gemini calls without modifying your application code, run your app with Braintrust's import hook. The hook patches the Google GenAI SDK at startup, so calls from an unwrapped client are traced automatically.

  ```javascript title="trace-gemini-auto.js" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { GoogleGenAI } from "@google/genai";
  import { initLogger } from "braintrust";

  initLogger({
    projectName: "My Project", // Replace with your project name
    apiKey: process.env.BRAINTRUST_API_KEY,
  });

  const client = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

  const response = await client.models.generateContent({
    model: "gemini-3.6-flash",
    contents: "What is the capital of France?",
  });
  console.log(response.text);
  ```

  Run your app with the import hook:

  ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  node --import braintrust/hook.mjs trace-gemini-auto.js
  ```

  The auto-instrumentation example uses plain JavaScript so `node --import` can run the file directly. The Braintrust APIs work the same in TypeScript projects — compile your TypeScript to JavaScript, then run the compiled file with the import hook.

  <Note>
    If you're using a bundler, see [Trace LLM calls](/docs/instrument/trace-llm-calls#auto-instrumentation) for plugin and loader setup.
  </Note>

  <h3 id="manual-instrumentation-typescript">
    Manual instrumentation
  </h3>

  To trace Gemini calls manually, wrap the Google GenAI module yourself with `wrapGoogleGenAI`. Every call from the wrapped client is then logged to Braintrust.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import * as googleGenAI from "@google/genai";
  import { wrapGoogleGenAI, initLogger } from "braintrust";

  // Initialize Braintrust tracing
  initLogger({ projectName: "My Project" });

  // Use wrapGoogleGenAI to wrap the Google GenAI module for automatic tracing
  const { GoogleGenAI } = wrapGoogleGenAI(googleGenAI);

  // Create a native Google GenAI client
  const client = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY || "",
  });

  // All API calls are automatically logged
  const response = await client.models.generateContent({
    model: "gemini-3.6-flash",
    contents: "What is machine learning?",
    config: {
      maxOutputTokens: 100,
    },
  });
  console.log(response.text);
  ```

  <h3 id="gateway-typescript">
    Gateway
  </h3>

  To route Gemini calls through the [Braintrust gateway](/docs/deploy/gateway), point the OpenAI SDK at the gateway base URL with your Braintrust API key. Routing and logging happen server-side, so you can reach Gemini through any [supported provider's SDK](/docs/integrations/ai-providers).

  Install the `braintrust` and `openai` packages.

  <CodeGroup>
    ```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    pnpm add braintrust openai
    ```

    ```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    npm install braintrust openai
    ```
  </CodeGroup>

  Initialize the client and make a request to a Gemini model through the gateway.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { OpenAI } from "openai";

  const client = new OpenAI({
    baseURL: "https://gateway.braintrust.dev/v1",
    apiKey: process.env.BRAINTRUST_API_KEY,
  });

  const response = await client.chat.completions.create({
    model: "gemini-3.6-flash",
    messages: [{ role: "user", content: "Hello, world!" }],
  });
  ```

  <h4 id="gateway-logging-typescript">
    Log to a project
  </h4>

  To log gateway calls to a specific project, initialize a logger with `initLogger`.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { OpenAI } from "openai";
  import { initLogger } from "braintrust";

  initLogger({
    projectName: "My Project",
    apiKey: process.env.BRAINTRUST_API_KEY,
  });

  const client = new OpenAI({
    baseURL: "https://gateway.braintrust.dev/v1",
    apiKey: process.env.BRAINTRUST_API_KEY,
  });

  // All API calls are automatically logged
  const result = await client.chat.completions.create({
    model: "gemini-3.6-flash",
    messages: [{ role: "user", content: "What is machine learning?" }],
  });
  ```

  <h4 id="gateway-streaming-typescript">
    Streaming
  </h4>

  Stream Gemini responses through the gateway.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  const stream = await client.chat.completions.create({
    model: "gemini-3.6-flash",
    messages: [{ role: "user", content: "Count to 10" }],
    stream: true,
  });

  for await (const chunk of stream) {
    process.stdout.write(chunk.choices[0]?.delta?.content || "");
  }
  ```

  <h4 id="gateway-embeddings-typescript">
    Embeddings
  </h4>

  The gateway also supports Gemini's native `embedContent` and `batchEmbedContents` endpoints, including multimodal text and image content. See [Generate embeddings](/docs/deploy/gateway#generate-embeddings) for an example.

  <h3 id="streaming-typescript">
    Streaming
  </h3>

  Stream responses from the native Google GenAI client with automatic tracing.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  const stream = await client.models.generateContentStream({
    model: "gemini-3.6-flash",
    contents: "Count from 1 to 10 slowly.",
    config: {
      maxOutputTokens: 200,
    },
  });

  // All streaming chunks are automatically logged
  for await (const chunk of stream) {
    if (chunk.text) {
      process.stdout.write(chunk.text);
    }
  }
  ```

  The wrapper aggregates streamed chunks and records streaming token metrics.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import * as googleGenAI from "@google/genai";
  import { wrapGoogleGenAI, initLogger } from "braintrust";

  // Setup automatic tracing
  initLogger({ projectName: "My Project" });
  const { GoogleGenAI } = wrapGoogleGenAI(googleGenAI);

  const client = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY || "",
  });

  // Stream responses - automatically tracked
  const stream = await client.models.generateContentStream({
    model: "gemini-3.6-flash",
    contents: "Write a story about a robot learning to paint.",
    config: {
      maxOutputTokens: 500,
    },
  });

  // Streaming automatically tracks:
  // - time_to_first_token
  // - prompt_tokens, completion_tokens, total_tokens
  // - prompt_cached_tokens (if using caching)
  for await (const chunk of stream) {
    if (chunk.text) {
      process.stdout.write(chunk.text);
    }
  }
  ```

  <h3 id="structured-outputs-typescript">
    Structured outputs
  </h3>

  Gemini supports structured JSON outputs using response schemas.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import * as googleGenAI from "@google/genai";
  import { wrapGoogleGenAI, initLogger } from "braintrust";

  // Setup automatic tracing
  initLogger({ projectName: "My Project" });
  const { GoogleGenAI } = wrapGoogleGenAI(googleGenAI);

  const client = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY || "",
  });

  // Define a schema for the response
  interface Person {
    name: string;
    age: number;
    occupation: string;
  }

  const response = await client.models.generateContent({
    model: "gemini-3.6-flash",
    contents:
      "Extract information about: John Smith is a 30-year-old software engineer.",
    config: {
      responseMimeType: "application/json",
      responseSchema: {
        type: "object",
        properties: {
          name: { type: "string" },
          age: { type: "number" },
          occupation: { type: "string" },
        },
        required: ["name", "age", "occupation"],
      },
      maxOutputTokens: 200,
    },
  });

  // Parse the JSON response
  const personData: Person = JSON.parse(response.text);
  console.log(`Name: ${personData.name}, Age: ${personData.age}`);
  ```

  <h3 id="function-calling-typescript">
    Function calling
  </h3>

  Gemini supports function calling for building AI agents with tools.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import * as googleGenAI from "@google/genai";
  import { wrapGoogleGenAI, initLogger } from "braintrust";

  // Setup automatic tracing
  initLogger({ projectName: "My Project" });
  const { GoogleGenAI } = wrapGoogleGenAI(googleGenAI);

  const client = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY || "",
  });

  // Define functions for the model to call
  function getWeather(location: string, unit: string = "celsius"): string {
    // In a real app, this would call a weather API
    return `22 degrees ${unit} and sunny in ${location}`;
  }

  function searchWeb(query: string): string {
    return `Search results for: ${query}`;
  }

  // Define function declarations
  const tools = [
    {
      functionDeclarations: [
        {
          name: "get_weather",
          description: "Get the current weather for a location",
          parameters: {
            type: "object",
            properties: {
              location: {
                type: "string",
                description: "The city and state, e.g. San Francisco, CA",
              },
              unit: {
                type: "string",
                enum: ["celsius", "fahrenheit"],
                description: "The unit of temperature",
              },
            },
            required: ["location"],
          },
        },
        {
          name: "search_web",
          description: "Search the web for information",
          parameters: {
            type: "object",
            properties: {
              query: {
                type: "string",
                description: "The search query",
              },
            },
            required: ["query"],
          },
        },
      ],
    },
  ];

  // Generate with tools
  const response = await client.models.generateContent({
    model: "gemini-3.6-flash",
    contents:
      "What's the weather in Paris and what tourist sites should I visit?",
    config: {
      tools: tools,
      maxOutputTokens: 500,
    },
  });

  // Handle function calls
  if (response.candidates[0].content.parts) {
    for (const part of response.candidates[0].content.parts) {
      if (part.functionCall) {
        const fc = part.functionCall;
        console.log(`Function: ${fc.name}`);
        console.log(`Arguments: ${JSON.stringify(fc.args)}`);

        // Execute the function
        if (fc.name === "get_weather") {
          const result = getWeather(fc.args.location, fc.args.unit);
          // Send result back to model for final response
        }
      }
    }
  }
  ```

  <h3 id="multimodal-content-typescript">
    Multimodal content
  </h3>

  Gemini models support multimodal inputs including images, audio, and video.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import * as googleGenAI from "@google/genai";
  import { wrapGoogleGenAI, initLogger } from "braintrust";
  import * as fs from "fs";

  // Setup automatic tracing
  initLogger({ projectName: "My Project" });
  const { GoogleGenAI } = wrapGoogleGenAI(googleGenAI);

  const client = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY || "",
  });

  // Image analysis
  const imageData = fs.readFileSync("image.jpg");

  const response = await client.models.generateContent({
    model: "gemini-3.6-flash",
    contents: [
      { text: "What's in this image?" },
      {
        inlineData: {
          mimeType: "image/jpeg",
          data: imageData.toString("base64"),
        },
      },
    ],
  });

  // Audio transcription
  const audioData = fs.readFileSync("audio.mp3");

  const audioResponse = await client.models.generateContent({
    model: "gemini-3.6-flash",
    contents: [
      { text: "Transcribe this audio:" },
      {
        inlineData: {
          mimeType: "audio/mp3",
          data: audioData.toString("base64"),
        },
      },
    ],
  });

  // The wrapper automatically handles binary data serialization
  // Binary attachments are converted to Braintrust Attachment objects
  ```

  <h3 id="reasoning-models-typescript">
    Reasoning models
  </h3>

  Gemini 3 models like `gemini-3.6-flash` and `gemini-3.1-pro` have built-in reasoning capabilities enabled by default. Configure reasoning behavior with `thinkingConfig`.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import * as googleGenAI from "@google/genai";
  import { wrapGoogleGenAI, initLogger } from "braintrust";

  // Setup automatic tracing
  initLogger({ projectName: "My Project" });
  const { GoogleGenAI } = wrapGoogleGenAI(googleGenAI);

  const client = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY || "",
  });

  // Use reasoning model - reasoning tokens are automatically tracked
  const response = await client.models.generateContent({
    model: "gemini-3.6-flash",
    contents: "What is the derivative of x^2 + 3x + 5? Think step by step.",
    config: {
      maxOutputTokens: 1000,
    },
  });

  // The response includes both the reasoning and final answer
  console.log(response.text);

  // Metrics automatically include reasoning tokens
  // The wrapper captures completion_reasoning_tokens in the metrics
  ```

  <h3 id="context-caching-typescript">
    Context caching
  </h3>

  Gemini supports context caching for efficient reuse of large contexts.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import * as googleGenAI from "@google/genai";
  import { wrapGoogleGenAI, initLogger } from "braintrust";

  // Setup automatic tracing
  initLogger({ projectName: "My Project" });
  const { GoogleGenAI } = wrapGoogleGenAI(googleGenAI);

  const client = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY || "",
  });

  // Create a cache for a large document
  const documentContent = "... very long document content ...";

  // Note: Caching API requires the full Vertex AI SDK
  // This example shows the structure - refer to Google's documentation
  // for complete caching implementation

  const response = await client.models.generateContent({
    model: "gemini-3.6-flash",
    contents: "Summarize the key points from the document",
    config: {
      // cachedContent would be configured here
      maxOutputTokens: 500,
    },
  });

  // The wrapper tracks cached tokens in metrics
  // Look for prompt_cached_tokens in the logged metrics
  ```

  <h3 id="advanced-tracing-typescript">
    Error handling, attachments, and masking sensitive data
  </h3>

  To learn more about these topics, check out the [customize traces](/docs/instrument/advanced-tracing) guide.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { OpenAI } from "openai";
  import "@braintrust/proxy/types"; // for type safety

  const client = new OpenAI({
    baseURL: "https://gateway.braintrust.dev/v1",
    apiKey: process.env.BRAINTRUST_API_KEY,
  });

  const response = await client.chat.completions.create({
    model: "gemini-3.6-flash",
    reasoning_enabled: true,
    reasoning_budget: 1024,
    messages: [{ role: "user", content: "How many rs in 'ferrocarril'?" }],
  });

  console.log(response.choices[0].reasoning); // Access reasoning steps
  ```

  <Tip>
    To learn more about multimodal support, attachments, error handling, and masking sensitive data with Gemini, visit the [customize traces](/docs/instrument/advanced-tracing) guide.
  </Tip>

  <h3 id="what-traced-typescript">
    What Braintrust traces
  </h3>

  Braintrust captures:

  * Content generation spans (`generate_content` and `generate_content_stream`), with the request as input and the full response as output. Streaming adds time to first token.
  * Embedding spans (`embed_content`), with embedding count and length and token usage.
  * Interaction spans (`create_interaction`) for foreground `interactions.create` calls, including streaming, with the interaction input, output, and usage.
  * Token metrics: prompt, completion, total (`tokens`), cached (`prompt_cached_tokens`), reasoning (`completion_reasoning_tokens`), and audio and image modality tokens.
  * Google Search grounding metadata on grounded responses.
  * Binary inputs (images, audio, and documents) uploaded as Braintrust [attachments](/docs/instrument/attachments).

  <h3 id="tracing-resources-typescript">
    Tracing resources
  </h3>

  * [Google GenAI SDK reference](https://googleapis.github.io/js-genai/) for the API surface being traced.
  * [`braintrust` on npm](https://www.npmjs.com/package/braintrust) for the tracing package.
  * [Trace LLM calls](/docs/instrument/trace-llm-calls) for tracing patterns across providers.

  <h2 id="evals-typescript">
    Evals
  </h2>

  Evaluate the output of Gemini models by running experiments with Braintrust `Eval`. Each eval combines a dataset, a task, and one or more scorers. To learn more, see the [Experiments](/docs/evaluate/run-evaluations) guide.

  <h3 id="evals-native-typescript">
    Native SDK
  </h3>

  Run experiments that call Gemini through the native Google GenAI SDK.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import * as googleGenAI from "@google/genai";
  import { Eval, wrapGoogleGenAI, initLogger } from "braintrust";

  // Setup tracing
  initLogger({ projectName: "Gemini Evaluation" });
  const { GoogleGenAI } = wrapGoogleGenAI(googleGenAI);

  const client = new GoogleGenAI({
    apiKey: process.env.GEMINI_API_KEY || "",
  });

  Eval("Gemini Native Evaluation", {
    data: () => [
      { input: "What is 2+2?", expected: "4" },
      { input: "What is the capital of France?", expected: "Paris" },
    ],
    task: async (input) => {
      const response = await client.models.generateContent({
        model: "gemini-3.6-flash",
        contents: input,
        config: {
          maxOutputTokens: 100,
        },
      });
      return response.text;
    },
    scores: [
      {
        name: "accuracy",
        scorer: (args) => (args.output === args.expected ? 1 : 0),
      },
    ],
  });
  ```

  <h3 id="evals-gateway-typescript">
    Gateway
  </h3>

  Run experiments that call Gemini through the Braintrust gateway.

  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { Eval } from "braintrust";
  import { OpenAI } from "openai";

  const client = new OpenAI({
    baseURL: "https://gateway.braintrust.dev/v1",
    apiKey: process.env.BRAINTRUST_API_KEY,
  });

  Eval("Gemini Evaluation", {
    data: () => [
      { input: "What is 2+2?", expected: "4" },
      { input: "What is the capital of France?", expected: "Paris" },
    ],
    task: async (input) => {
      const response = await client.chat.completions.create({
        model: "gemini-3.6-flash",
        messages: [{ role: "user", content: input }],
      });
      return response.choices[0].message.content;
    },
    scores: [
      {
        name: "accuracy",
        scorer: (args) => (args.output === args.expected ? 1 : 0),
      },
    ],
  });
  ```
</View>

<View title="Python" icon="https://img.logo.dev/python.org?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  Trace Gemini calls from your Python application, then run experiments against Gemini models.

  <h2 id="tracing-python">
    Tracing
  </h2>

  Trace Gemini calls to Braintrust with the native Google GenAI SDK, or route them through the Braintrust gateway.

  <h3 id="setup-python">
    Setup
  </h3>

  Install the Braintrust and Google GenAI SDKs, then set your API keys.

  <Steps>
    <Step title="Install packages">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      pip install braintrust google-genai
      ```
    </Step>

    <Step title="Set environment variables">
      ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      GEMINI_API_KEY=<your-gemini-api-key>
      BRAINTRUST_API_KEY=<your-braintrust-api-key>

      # For organizations on the EU data plane, use https://api-eu.braintrust.dev
      # For self-hosted deployments, use your data plane URL
      # BRAINTRUST_API_URL=<your-braintrust-api-url-here>
      ```
    </Step>
  </Steps>

  <h3 id="auto-instrumentation-python">
    Auto-instrumentation
  </h3>

  To trace Gemini calls without modifying your application code, call `braintrust.auto_instrument()` at startup. It patches the Google GenAI SDK so calls from an unwrapped client are traced automatically.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  import braintrust
  from google.genai import Client

  # Call once at startup — all Gemini calls are traced automatically
  braintrust.auto_instrument()
  braintrust.init_logger(
      api_key=os.environ["BRAINTRUST_API_KEY"],
      project="My Project",
  )

  client = Client(api_key=os.environ["GEMINI_API_KEY"])
  response = client.models.generate_content(
      model="gemini-3.6-flash",
      contents="What is the capital of France?",
  )
  print(response.text)
  ```

  <Note>
    `braintrust.auto_instrument()` enables Google GenAI by default alongside every other supported Python integration. See [Trace LLM calls](/docs/instrument/trace-llm-calls#auto-instrumentation) to disable specific integrations.
  </Note>

  <h3 id="manual-instrumentation-python">
    Manual instrumentation
  </h3>

  To trace Gemini calls manually, call `setup_genai` yourself to patch the Google GenAI client. Every subsequent call is then logged to Braintrust.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  from braintrust.wrappers.google_genai import setup_genai
  from google.genai import types
  from google.genai.client import Client

  # Use setup_genai to automatically trace all Google GenAI API calls
  setup_genai(project_name="My Project")

  # Create a native Google GenAI client
  client = Client(api_key=os.environ["GEMINI_API_KEY"])

  # All API calls are automatically logged
  response = client.models.generate_content(
      model="gemini-3.6-flash",
      contents="What is machine learning?",
      config=types.GenerateContentConfig(
          max_output_tokens=100,
      ),
  )
  print(response.text)
  ```

  <h3 id="gateway-python">
    Gateway
  </h3>

  To route Gemini calls through the [Braintrust gateway](/docs/deploy/gateway), point the OpenAI SDK at the gateway base URL with your Braintrust API key. Routing and logging happen server-side, so you can reach Gemini through any [supported provider's SDK](/docs/integrations/ai-providers).

  Install the `braintrust` and `openai` packages.

  ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  pip install braintrust openai
  ```

  Initialize the client and make a request to a Gemini model through the gateway.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  from openai import OpenAI

  client = OpenAI(
      base_url="https://gateway.braintrust.dev/v1",
      api_key=os.environ["BRAINTRUST_API_KEY"],
  )

  response = client.chat.completions.create(
      model="gemini-3.6-flash",
      messages=[{"role": "user", "content": "Hello, world!"}],
  )
  ```

  <h4 id="gateway-logging-python">
    Log to a project
  </h4>

  To log gateway calls to a specific project, initialize a logger with `init_logger`.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  from braintrust import init_logger
  from openai import OpenAI

  init_logger(project="My Project")

  client = OpenAI(
      base_url="https://gateway.braintrust.dev/v1",
      api_key=os.environ["BRAINTRUST_API_KEY"],
  )

  # All API calls are automatically logged
  result = client.chat.completions.create(
      model="gemini-3.6-flash",
      messages=[{"role": "user", "content": "What is machine learning?"}],
  )
  ```

  <h4 id="gateway-streaming-python">
    Streaming
  </h4>

  Stream Gemini responses through the gateway.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  stream = client.chat.completions.create(
      model="gemini-3.6-flash",
      messages=[{"role": "user", "content": "Count to 10"}],
      stream=True,
  )

  for chunk in stream:
      if chunk.choices[0].delta.content:
          print(chunk.choices[0].delta.content, end="")
  ```

  <h4 id="gateway-embeddings-python">
    Embeddings
  </h4>

  The gateway also supports Gemini's native `embedContent` and `batchEmbedContents` endpoints, including multimodal text and image content. See [Generate embeddings](/docs/deploy/gateway#generate-embeddings) for an example.

  <h3 id="streaming-python">
    Streaming
  </h3>

  Stream responses from the native Google GenAI client with automatic tracing.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  stream = client.models.generate_content_stream(
      model="gemini-3.6-flash",
      contents="Count from 1 to 10 slowly.",
      config=types.GenerateContentConfig(
          max_output_tokens=200,
      ),
  )

  # All streaming chunks are automatically logged
  for chunk in stream:
      if chunk.text:
          print(chunk.text, end="")
  ```

  The wrapper aggregates streamed chunks and records streaming token metrics, including time to first token. Async streaming is traced the same way.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  from braintrust.wrappers.google_genai import setup_genai
  from google import genai
  from google.genai import types

  # Setup automatic tracing
  setup_genai(project_name="My Project")
  client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

  # Stream responses - automatically tracked
  stream = client.models.generate_content_stream(
      model="gemini-3.6-flash",
      contents="Write a story about a robot learning to paint.",
      config=types.GenerateContentConfig(
          max_output_tokens=500,
      ),
  )

  # Streaming automatically tracks:
  # - time_to_first_token
  # - prompt_tokens, completion_tokens, total_tokens
  # - prompt_cached_tokens (if using caching)
  for chunk in stream:
      if chunk.text:
          print(chunk.text, end="")

  # Async streaming is also supported
  import asyncio


  async def stream_async():
      stream = await client.aio.models.generate_content_stream(
          model="gemini-3.6-flash",
          contents="Count from 1 to 10 slowly.",
          config=types.GenerateContentConfig(
              max_output_tokens=200,
          ),
      )

      async for chunk in stream:
          if chunk.text:
              print(chunk.text, end="")


  asyncio.run(stream_async())
  ```

  <h3 id="structured-outputs-python">
    Structured outputs
  </h3>

  Gemini supports structured JSON outputs using response schemas.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os
  from typing import TypedDict

  from braintrust.wrappers.google_genai import setup_genai
  from google import genai
  from google.genai import types

  # Setup automatic tracing
  setup_genai(project_name="My Project")
  client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])


  # Define a schema for the response
  class Person(TypedDict):
      name: str
      age: int
      occupation: str


  response = client.models.generate_content(
      model="gemini-3.6-flash",
      contents="Extract information about: John Smith is a 30-year-old software engineer.",
      config=types.GenerateContentConfig(
          response_mime_type="application/json",
          response_schema=Person,
          max_output_tokens=200,
      ),
  )

  # Parse the JSON response
  import json

  person_data = json.loads(response.text)
  print(f"Name: {person_data['name']}, Age: {person_data['age']}")
  ```

  <h3 id="function-calling-python">
    Function calling
  </h3>

  Gemini supports function calling for building AI agents with tools.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  from braintrust.wrappers.google_genai import setup_genai
  from google import genai
  from google.genai import types

  # Setup automatic tracing
  setup_genai(project_name="My Project")
  client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])


  # Define functions for the model to call
  def get_weather(location: str, unit: str = "celsius") -> str:
      """Get the current weather for a location.

      Args:
          location: The city and state, e.g. San Francisco, CA
          unit: The unit of temperature (celsius or fahrenheit)
      """
      # In a real app, this would call a weather API
      return f"22 degrees {unit} and sunny in {location}"


  def search_web(query: str) -> str:
      """Search the web for information.

      Args:
          query: The search query
      """
      return f"Search results for: {query}"


  # Generate with tools
  response = client.models.generate_content(
      model="gemini-3.6-flash",
      contents="What's the weather in Paris and what tourist sites should I visit?",
      config=types.GenerateContentConfig(
          tools=[get_weather, search_web],  # Pass functions as tools
          max_output_tokens=500,
      ),
  )

  # Handle function calls
  if response.candidates[0].content.parts:
      for part in response.candidates[0].content.parts:
          if hasattr(part, "function_call"):
              fc = part.function_call
              print(f"Function: {fc.name}")
              print(f"Arguments: {fc.args}")

              # Execute the function
              if fc.name == "get_weather":
                  result = get_weather(**fc.args)
                  # Send result back to model for final response
  ```

  <h3 id="multimodal-content-python">
    Multimodal content
  </h3>

  Gemini models support multimodal inputs including images, audio, and video.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  from braintrust.wrappers.google_genai import setup_genai
  from google import genai
  from google.genai import types

  # Setup automatic tracing
  setup_genai(project_name="My Project")
  client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

  # Image analysis
  with open("image.jpg", "rb") as f:
      image_data = f.read()

  response = client.models.generate_content(
      model="gemini-3.6-flash",
      contents=["What's in this image?", types.Part.from_bytes(data=image_data, mime_type="image/jpeg")],
  )

  # Audio transcription
  with open("audio.mp3", "rb") as f:
      audio_data = f.read()

  response = client.models.generate_content(
      model="gemini-3.6-flash",
      contents=["Transcribe this audio:", types.Part.from_bytes(data=audio_data, mime_type="audio/mp3")],
  )

  # The wrapper automatically handles binary data serialization
  # Binary attachments are converted to Braintrust Attachment objects
  ```

  <h3 id="reasoning-models-python">
    Reasoning models
  </h3>

  Gemini 3 models like `gemini-3.6-flash` and `gemini-3.1-pro` have built-in reasoning capabilities enabled by default. Configure reasoning behavior with `thinkingConfig`.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  from braintrust.wrappers.google_genai import setup_genai
  from google import genai
  from google.genai import types

  # Setup automatic tracing
  setup_genai(project_name="My Project")
  client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

  # Use reasoning model - reasoning tokens are automatically tracked
  response = client.models.generate_content(
      model="gemini-3.6-flash",
      contents="What is the derivative of x^2 + 3x + 5? Think step by step.",
      config=types.GenerateContentConfig(
          max_output_tokens=1000,
      ),
  )

  # The response includes both the reasoning and final answer
  print(response.text)


  # Metrics automatically include reasoning tokens
  # The wrapper captures completion_reasoning_tokens in the metrics

  ```

  <h3 id="context-caching-python">
    Context caching
  </h3>

  Gemini supports context caching for efficient reuse of large contexts.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os
  from datetime import timedelta

  from braintrust.wrappers.google_genai import setup_genai
  from google import genai
  from google.genai import caching, types

  # Setup automatic tracing
  setup_genai(project_name="My Project")
  client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

  # Create a cache for a large document
  document_content = "... very long document content ..."

  cache = caching.CachedContent.create(
      model="gemini-3.6-flash",
      contents=[document_content],
      ttl=timedelta(hours=1),
  )

  # Use the cache in subsequent requests
  response = client.models.generate_content(
      model="gemini-3.6-flash",
      contents="Summarize the key points from the document",
      config=types.GenerateContentConfig(
          cached_content=cache,
          max_output_tokens=500,
      ),
  )

  # The wrapper tracks cached tokens in metrics
  # Look for prompt_cached_tokens in the logged metrics
  ```

  <h3 id="advanced-tracing-python">
    Error handling, attachments, and masking sensitive data
  </h3>

  To learn more about these topics, check out the [customize traces](/docs/instrument/advanced-tracing) guide.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  from openai import OpenAI

  client = OpenAI(
      base_url="https://gateway.braintrust.dev/v1",
      api_key=os.environ["BRAINTRUST_API_KEY"],
  )

  response = client.chat.completions.create(
      model="gemini-3.6-flash",
      reasoning_enabled=True,
      reasoning_budget=1024,
      messages=[{"role": "user", "content": "How many rs in 'ferrocarril'?"}],
  )

  print(response.choices[0].reasoning)  # Access reasoning steps
  ```

  <Tip>
    To learn more about multimodal support, attachments, error handling, and masking sensitive data with Gemini, visit the [customize traces](/docs/instrument/advanced-tracing) guide.
  </Tip>

  <h3 id="what-traced-python">
    What Braintrust traces
  </h3>

  Braintrust captures:

  * Content generation spans (`generate_content`, sync and async), with the model, contents, and config as input and the full response as output.
  * Streaming content spans (`generate_content_stream`), with the aggregated response and time to first token alongside the token metrics.
  * Embedding spans (`embed_content`), with embedding count and length, token usage, and billable character count.
  * Image generation spans (`generate_images`), with generated-image metadata and attachments.
  * Interaction spans (`interactions.create`, `interactions.get`, `interactions.cancel`, and `interactions.delete`, sync and async, including streaming), with interaction inputs, outputs, status, and usage.
  * Tool spans created around interactions, with tool arguments, results, and tool metadata.
  * Token metrics for content and interaction calls: prompt, completion, total (`tokens`), cached (`prompt_cached_tokens`), reasoning (`completion_reasoning_tokens`), and audio and image modality tokens.
  * Google Search grounding metadata (web search queries, grounding chunks, and grounding supports) on grounded responses.
  * Binary inputs (images, audio, and documents) uploaded as Braintrust [attachments](/docs/instrument/attachments).

  <h3 id="tracing-resources-python">
    Tracing resources
  </h3>

  * [Google GenAI SDK reference](https://googleapis.github.io/python-genai/) for the API surface being traced.
  * [`braintrust` on PyPI](https://pypi.org/project/braintrust/) for the tracing package.
  * [Trace LLM calls](/docs/instrument/trace-llm-calls) for tracing patterns across providers.

  <h2 id="evals-python">
    Evals
  </h2>

  Evaluate the output of Gemini models by running experiments with Braintrust `Eval`. Each eval combines a dataset, a task, and one or more scorers. To learn more, see the [Experiments](/docs/evaluate/run-evaluations) guide.

  <h3 id="evals-native-python">
    Native SDK
  </h3>

  Run experiments that call Gemini through the native Google GenAI SDK.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  from braintrust import Eval
  from braintrust.wrappers.google_genai import setup_genai
  from google.genai import types
  from google.genai.client import Client

  # Setup tracing
  setup_genai(project_name="Gemini Evaluation")

  client = Client(api_key=os.environ["GEMINI_API_KEY"])


  def task(input):
      response = client.models.generate_content(
          model="gemini-3.6-flash",
          contents=input,
          config=types.GenerateContentConfig(
              max_output_tokens=100,
          ),
      )
      return response.text


  def accuracy_scorer(output, expected, **kwargs):
      return 1 if output == expected else 0


  Eval(
      "Gemini Native Evaluation",
      data=[
          {"input": "What is 2+2?", "expected": "4"},
          {"input": "What is the capital of France?", "expected": "Paris"},
      ],
      task=task,
      scores=[accuracy_scorer],
  )
  ```

  <h3 id="evals-gateway-python">
    Gateway
  </h3>

  Run experiments that call Gemini through the Braintrust gateway.

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import os

  from braintrust import Eval
  from openai import OpenAI

  client = OpenAI(
      base_url="https://gateway.braintrust.dev/v1",
      api_key=os.environ["BRAINTRUST_API_KEY"],
  )


  def task(input):
      response = client.chat.completions.create(
          model="gemini-3.6-flash",
          messages=[{"role": "user", "content": input}],
      )
      return response.choices[0].message.content


  def accuracy_scorer(output, expected, **kwargs):
      return 1 if output == expected else 0


  Eval(
      "Gemini Evaluation",
      data=[
          {"input": "What is 2+2?", "expected": "4"},
          {"input": "What is the capital of France?", "expected": "Paris"},
      ],
      task=task,
      scores=[accuracy_scorer],
  )
  ```
</View>

<View title="Go" icon="https://img.logo.dev/go.dev?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  Trace Gemini calls from your Go application.

  <h2 id="tracing-go">
    Tracing
  </h2>

  Trace Gemini calls made through the [Google GenAI Go SDK](https://pkg.go.dev/google.golang.org/genai), either by attaching a traced HTTP client manually or by applying it automatically at compile time with Orchestrion.

  <h3 id="setup-go">
    Setup
  </h3>

  Install the Braintrust Go SDK and the genai contrib alongside the Google GenAI SDK, then set your API keys.

  <Steps>
    <Step title="Install packages">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      go get github.com/braintrustdata/braintrust-sdk-go
      go get github.com/braintrustdata/braintrust-sdk-go/trace/contrib/genai
      go get google.golang.org/genai
      ```
    </Step>

    <Step title="Set environment variables">
      ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      BRAINTRUST_API_KEY=<your-braintrust-api-key>
      GEMINI_API_KEY=<your-gemini-api-key>
      ```
    </Step>
  </Steps>

  <h3 id="auto-instrumentation-go">
    Auto-instrumentation
  </h3>

  To trace Gemini calls without modifying your application code, build your app with [Orchestrion](https://github.com/DataDog/orchestrion), a compile-time tool that rewrites every `genai.NewClient` call to attach Braintrust's traced HTTP client automatically.

  <Steps>
    <Step title="Install Orchestrion">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      go install github.com/DataDog/orchestrion@v1.6.1
      ```
    </Step>

    <Step title="Create orchestrion.tool.go in your project root">
      ```go title="orchestrion.tool.go" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      //go:build tools

      package main

      import (
      	_ "github.com/DataDog/orchestrion"
      	_ "github.com/braintrustdata/braintrust-sdk-go/trace/contrib/genai"
      )
      ```
    </Step>

    <Step title="Write your app">
      Orchestrion instruments every `genai.NewClient` call at build time, so no HTTP client wiring is needed.

      ```go theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      package main

      import (
      	"context"
      	"fmt"
      	"log"
      	"os"

      	"go.opentelemetry.io/otel"
      	"go.opentelemetry.io/otel/sdk/trace"
      	"google.golang.org/genai"

      	"github.com/braintrustdata/braintrust-sdk-go"
      )

      func main() {
      	tp := trace.NewTracerProvider()
      	defer tp.Shutdown(context.Background())
      	otel.SetTracerProvider(tp)

      	bt, err := braintrust.New(tp,
      		braintrust.WithProject("gemini-example"),
      		braintrust.WithBlockingLogin(true),
      	)
      	if err != nil {
      		log.Fatal(err)
      	}

      	ctx, span := otel.Tracer("gemini-example").Start(context.Background(), "trace-gemini")
      	defer span.End()

      	// Orchestrion rewrites genai.NewClient to attach Braintrust tracing at build time
      	client, err := genai.NewClient(ctx, &genai.ClientConfig{
      		APIKey:  os.Getenv("GEMINI_API_KEY"),
      		Backend: genai.BackendGeminiAPI,
      	})
      	if err != nil {
      		log.Fatal(err)
      	}

      	resp, err := client.Models.GenerateContent(ctx, "gemini-3.6-flash",
      		genai.Text("What is the capital of France?"), nil)
      	if err != nil {
      		log.Fatal(err)
      	}

      	fmt.Println(resp.Text())
      	fmt.Printf("View trace: %s\n", bt.Permalink(span))
      }
      ```
    </Step>

    <Step title="Build with Orchestrion">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      orchestrion go build ./...
      ```
    </Step>
  </Steps>

  <h3 id="manual-instrumentation-go">
    Manual instrumentation
  </h3>

  To trace Gemini calls manually, attach Braintrust's traced HTTP client yourself by passing `tracegenai.Client()` as the `HTTPClient` in your `genai.ClientConfig`. Every call from that client is then logged to Braintrust.

  ```go theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  package main

  import (
  	"context"
  	"fmt"
  	"log"
  	"os"

  	"go.opentelemetry.io/otel"
  	"go.opentelemetry.io/otel/sdk/trace"
  	"google.golang.org/genai"

  	"github.com/braintrustdata/braintrust-sdk-go"
  	tracegenai "github.com/braintrustdata/braintrust-sdk-go/trace/contrib/genai"
  )

  func main() {
  	tp := trace.NewTracerProvider()
  	defer tp.Shutdown(context.Background())
  	otel.SetTracerProvider(tp)

  	bt, err := braintrust.New(tp,
  		braintrust.WithProject("gemini-example"),
  		braintrust.WithBlockingLogin(true),
  	)
  	if err != nil {
  		log.Fatal(err)
  	}

  	ctx, span := otel.Tracer("gemini-example").Start(context.Background(), "trace-gemini")
  	defer span.End()

  	// Attach Braintrust tracing through the genai HTTP client
  	client, err := genai.NewClient(ctx, &genai.ClientConfig{
  		HTTPClient: tracegenai.Client(),
  		APIKey:     os.Getenv("GEMINI_API_KEY"),
  		Backend:    genai.BackendGeminiAPI,
  	})
  	if err != nil {
  		log.Fatal(err)
  	}

  	resp, err := client.Models.GenerateContent(ctx, "gemini-3.6-flash",
  		genai.Text("What is the capital of France?"), nil)
  	if err != nil {
  		log.Fatal(err)
  	}

  	fmt.Println(resp.Text())
  	fmt.Printf("View trace: %s\n", bt.Permalink(span))
  }
  ```

  <h3 id="what-traced-go">
    What Braintrust traces
  </h3>

  Braintrust captures:

  * Content generation spans (`generate_content`), for `GenerateContent` and `GenerateContentStream`, with the model, contents, and config as input and the response as output. Time to first token is recorded on both.
  * Embedding spans (`embed_content`), for `EmbedContent` and `batchEmbedContents`, with a summary of embedding count and length.
  * Request metadata: provider, model, system instruction, tools and tool config, safety settings, cached content, and generation parameters (temperature, top-p, top-k, candidate count, max output tokens, stop sequences, response MIME type and schema, and thinking config).
  * Token metrics: prompt (`prompt_tokens`), completion (`completion_tokens`), total (`tokens`), cached (`prompt_cached_tokens`), and reasoning (`completion_reasoning_tokens`).

  <h3 id="tracing-resources-go">
    Tracing resources
  </h3>

  * [Google GenAI Go SDK](https://pkg.go.dev/google.golang.org/genai) for the API surface being traced.
  * [`braintrust-sdk-go`](https://github.com/braintrustdata/braintrust-sdk-go) for the tracing package.
  * [Trace LLM calls](/docs/instrument/trace-llm-calls) for tracing patterns across providers.
</View>

<View title="Java" icon="https://img.logo.dev/java.com?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  Trace Gemini calls from your Java application.

  <h2 id="tracing-java">
    Tracing
  </h2>

  Trace Gemini calls made through the native Google GenAI SDK, either by wrapping the client manually or by attaching the Braintrust Java agent at startup.

  <h3 id="setup-java">
    Setup
  </h3>

  Add the Braintrust and Google GenAI dependencies, then set your API keys.

  <Steps>
    <Step title="Add dependencies">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      # add to build.gradle dependencies{} block
      implementation 'dev.braintrust:braintrust-sdk-java:<version-goes-here>'
      implementation 'com.google.genai:google-genai:1.20.0'
      ```
    </Step>

    <Step title="Set environment variables">
      ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      GEMINI_API_KEY=<your-gemini-api-key>
      BRAINTRUST_API_KEY=<your-braintrust-api-key>

      # For organizations on the EU data plane, use https://api-eu.braintrust.dev
      # For self-hosted deployments, use your data plane URL
      # BRAINTRUST_API_URL=<your-braintrust-api-url-here>
      ```
    </Step>
  </Steps>

  <h3 id="auto-instrumentation-java">
    Auto-instrumentation
  </h3>

  To trace Gemini calls without modifying your application code, attach the [Braintrust Java agent](/docs/instrument/trace-llm-calls#auto-instrumentation) at JVM startup. The agent intercepts every Google GenAI client build and wraps it automatically, so no call to `BraintrustGenAI.wrap` is required.

  <Steps>
    <Step title="Add the agent dependency">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      # build.gradle
      configurations {
          braintrustAgent
      }

      dependencies {
          braintrustAgent 'dev.braintrust:braintrust-java-agent:+'
      }

      tasks.withType(JavaExec).configureEach {
          jvmArgs "-javaagent:${configurations.braintrustAgent.asPath}"
      }
      ```
    </Step>

    <Step title="Run your app">
      ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
      ./gradlew run
      ```

      Google GenAI clients built with `Client.builder()` in your application code are now instrumented automatically. The agent configures OpenTelemetry and the Braintrust exporter itself, so you only need to set `BRAINTRUST_API_KEY`.
    </Step>
  </Steps>

  <Note>
    Auto-instrumentation requires `com.google.genai:google-genai` version 1.18.0 or later.
  </Note>

  <h3 id="manual-instrumentation-java">
    Manual instrumentation
  </h3>

  To trace Gemini calls manually, wrap the Google GenAI client yourself with `BraintrustGenAI.wrap`. Every call from the wrapped client is then logged to Braintrust.

  ```java theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import com.google.genai.Client;
  import com.google.genai.types.GenerateContentConfig;
  import dev.braintrust.Braintrust;
  import dev.braintrust.instrumentation.genai.BraintrustGenAI;
  import io.opentelemetry.api.OpenTelemetry;

  class GeminiExample {
      public static void main(String[] args) {
          // Initialize Braintrust and create OpenTelemetry instance
          Braintrust braintrust = Braintrust.get();
          OpenTelemetry openTelemetry = braintrust.openTelemetryCreate();

          // Wrap the Google GenAI client for automatic tracing
          Client client = BraintrustGenAI.wrap(openTelemetry, new Client.Builder());

          // All API calls are automatically logged
          GenerateContentConfig config = GenerateContentConfig.builder()
              .maxOutputTokens(100)
              .build();

          var response = client.models.generateContent(
              "gemini-3.6-flash",
              "What is machine learning?",
              config
          );
          System.out.println(response.text());
      }
  }
  ```

  <h3 id="streaming-java">
    Streaming
  </h3>

  Stream responses from the native Google GenAI client.

  ```java theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import com.google.genai.Client;
  import com.google.genai.types.GenerateContentConfig;
  import dev.braintrust.Braintrust;
  import dev.braintrust.instrumentation.genai.BraintrustGenAI;
  import io.opentelemetry.api.OpenTelemetry;

  class GeminiStreamingExample {
      public static void main(String[] args) {
          Braintrust braintrust = Braintrust.get();
          OpenTelemetry openTelemetry = braintrust.openTelemetryCreate();
          Client client = BraintrustGenAI.wrap(openTelemetry, new Client.Builder());

          GenerateContentConfig config = GenerateContentConfig.builder()
              .maxOutputTokens(200)
              .build();

          var stream = client.models.generateContentStream(
              "gemini-3.6-flash",
              "Count from 1 to 10 slowly.",
              config
          );

          // All streaming chunks are automatically logged
          for (var chunk : stream) {
              String text = chunk.text();
              if (text != null && !text.isEmpty()) {
                  System.out.print(text);
              }
          }
      }
  }
  ```

  ```java theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import com.google.genai.Client;
  import com.google.genai.types.GenerateContentConfig;
  import dev.braintrust.Braintrust;
  import dev.braintrust.instrumentation.genai.BraintrustGenAI;
  import io.opentelemetry.api.OpenTelemetry;

  class GeminiStreamingMetricsExample {
      public static void main(String[] args) {
          // Setup automatic tracing
          Braintrust braintrust = Braintrust.get();
          OpenTelemetry openTelemetry = braintrust.openTelemetryCreate();
          Client client = BraintrustGenAI.wrap(openTelemetry, new Client.Builder());

          // Stream responses - automatically tracked
          GenerateContentConfig config = GenerateContentConfig.builder()
              .maxOutputTokens(500)
              .build();

          var stream = client.models.generateContentStream(
              "gemini-3.6-flash",
              "Write a story about a robot learning to paint.",
              config
          );

          // Streaming automatically tracks:
          // - time_to_first_token
          // - prompt_tokens, completion_tokens, total_tokens
          // - prompt_cached_tokens (if using caching)
          for (var chunk : stream) {
              if (chunk.text() != null) {
                  System.out.print(chunk.text());
              }
          }
      }
  }
  ```

  <h3 id="reasoning-models-java">
    Reasoning models
  </h3>

  Gemini 3 models like `gemini-3.6-flash` and `gemini-3.1-pro` have built-in reasoning capabilities enabled by default.

  ```java theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import com.google.genai.Client;
  import com.google.genai.types.GenerateContentConfig;
  import dev.braintrust.Braintrust;
  import dev.braintrust.instrumentation.genai.BraintrustGenAI;
  import io.opentelemetry.api.OpenTelemetry;

  class GeminiReasoningExample {
      public static void main(String[] args) {
          // Setup automatic tracing
          Braintrust braintrust = Braintrust.get();
          OpenTelemetry openTelemetry = braintrust.openTelemetryCreate();
          Client client = BraintrustGenAI.wrap(openTelemetry, new Client.Builder());

          // Use reasoning model - reasoning tokens are automatically tracked
          GenerateContentConfig config = GenerateContentConfig.builder()
              .maxOutputTokens(1000)
              .build();

          var response = client.models.generateContent(
              "gemini-3.6-flash",
              "What is the derivative of x^2 + 3x + 5? Think step by step.",
              config
          );

          // The response includes both the reasoning and final answer
          System.out.println(response.text());

          // Metrics automatically include reasoning tokens
          // The wrapper captures completion_reasoning_tokens in the metrics
      }
  }
  ```

  <h3 id="context-caching-java">
    Context caching
  </h3>

  Gemini supports context caching for efficient reuse of large contexts.

  ```java theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import com.google.genai.Client;
  import com.google.genai.types.GenerateContentConfig;
  import dev.braintrust.Braintrust;
  import dev.braintrust.instrumentation.genai.BraintrustGenAI;
  import io.opentelemetry.api.OpenTelemetry;

  class GeminiCachingExample {
      public static void main(String[] args) {
          // Setup automatic tracing
          Braintrust braintrust = Braintrust.get();
          OpenTelemetry openTelemetry = braintrust.openTelemetryCreate();
          Client client = BraintrustGenAI.wrap(openTelemetry, new Client.Builder());

          // Create a cache for a large document
          String documentContent = "... very long document content ...";

          // Note: Caching API requires the full Vertex AI SDK
          // This example shows the structure - refer to Google's documentation
          // for complete caching implementation

          GenerateContentConfig config = GenerateContentConfig.builder()
              // cachedContent would be configured here
              .maxOutputTokens(500)
              .build();

          var response = client.models.generateContent(
              "gemini-3.6-flash",
              "Summarize the key points from the document",
              config
          );

          // The wrapper tracks cached tokens in metrics
          // Look for prompt_cached_tokens in the logged metrics
      }
  }
  ```

  <h3 id="spring-ai-java">
    Use with Spring AI
  </h3>

  For Java applications using [Spring AI](https://spring.io/projects/spring-ai), integrate Braintrust by wrapping the underlying Google GenAI client and passing it to Spring AI's `GoogleGenAiChatModel`.

  ```java theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import com.google.genai.Client;
  import dev.braintrust.Braintrust;
  import dev.braintrust.config.BraintrustConfig;
  import dev.braintrust.instrumentation.genai.BraintrustGenAI;
  import io.opentelemetry.api.OpenTelemetry;
  import io.opentelemetry.api.trace.Tracer;

  // Spring AI imports (requires spring-ai-google-genai dependency)
  // import org.springframework.ai.chat.model.ChatModel;
  // import org.springframework.ai.chat.prompt.Prompt;
  // import org.springframework.ai.google.genai.GoogleGenAiChatModel;
  // import org.springframework.ai.google.genai.GoogleGenAiChatOptions;
  // import org.springframework.boot.CommandLineRunner;
  // import org.springframework.boot.SpringApplication;
  // import org.springframework.boot.autoconfigure.SpringBootApplication;
  // import org.springframework.context.annotation.Bean;

  // @SpringBootApplication
  class SpringAIExample {

      public static void main(String[] args) {
          // SpringApplication.run(SpringAIExample.class, args);

          // Key pattern for Spring AI integration:
          // 1. Initialize Braintrust
          Braintrust braintrust = Braintrust.get(BraintrustConfig.fromEnvironment());
          OpenTelemetry openTelemetry = braintrust.openTelemetryCreate();

          // 2. Wrap the Google GenAI client with Braintrust
          Client genAIClient = BraintrustGenAI.wrap(openTelemetry, new Client.Builder());

          // 3. Pass the wrapped client to Spring AI's GoogleGenAiChatModel
          // ChatModel chatModel = GoogleGenAiChatModel.builder()
          //     .genAIClient(genAIClient)
          //     .defaultOptions(
          //         GoogleGenAiChatOptions.builder()
          //             .model("gemini-3.6-flash")
          //             .temperature(0.0)
          //             .maxOutputTokens(50)
          //             .build())
          //     .build();

          // 4. Use the ChatModel in your Spring application
          // All calls through ChatModel are automatically traced to Braintrust
      }
  }
  ```

  This pattern works with all Spring AI features including streaming, function calling, and structured outputs. All calls through the `ChatModel` are automatically traced to Braintrust.

  <h3 id="what-traced-java">
    What Braintrust traces
  </h3>

  Braintrust captures:

  * Content generation spans (`generate_content`, sync and async), with the model, contents, and generation config as input and the full response as output.
  * Request metadata: provider, model, system instruction, tools and tool config, safety settings, cached content, and generation parameters (temperature, top-p, top-k, candidate count, max output tokens, stop sequences, response MIME type, and response schema).
  * Token metrics: prompt (`prompt_tokens`), completion (`completion_tokens`), total (`tokens`), and cached (`prompt_cached_tokens`).

  <h3 id="tracing-resources-java">
    Tracing resources
  </h3>

  * [google-genai for Java](https://github.com/googleapis/java-genai) for the API surface being traced.
  * [`braintrust-sdk-java`](https://github.com/braintrustdata/braintrust-sdk-java) for the tracing package.
  * [Trace LLM calls](/docs/instrument/trace-llm-calls) for tracing patterns across providers.
</View>

## Add Gemini as an AI provider

Add your Gemini API key to Braintrust to route requests through the gateway and use Gemini models from the playground.

<Steps>
  <Step title="Get a Gemini API key">
    Get a Gemini API key from [Google AI Studio](https://aistudio.google.com/app/apikey).
  </Step>

  <Step title="Add the key to Braintrust">
    Go to **<Icon icon="settings-2" /> Settings** > [**<Icon icon="sparkle" /> AI providers**](https://www.braintrust.dev/app/~/configuration/org/secrets) and add the Gemini API key as an organization or project [AI provider](/docs/admin/ai-providers).
  </Step>
</Steps>

<Note>
  API keys are stored as one-way cryptographic hashes, never in plaintext.
</Note>

### Gemini provider resources

* [AI providers](/docs/admin/ai-providers) for configuring provider keys and scopes.
* [Playgrounds](/docs/evaluate/playgrounds) for comparing Gemini models against other providers.
* [Google AI Studio](https://aistudio.google.com/) for managing Gemini API keys.
