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

# Anthropic

> Trace Anthropic SDK calls, evaluate Claude models, and route them through the Braintrust gateway

Braintrust integrates with [Anthropic](https://www.anthropic.com) so you can call Claude models from the Braintrust playground, API, and SDKs. Braintrust also traces Anthropic SDK calls from your application, including streaming, prompt caching, server-side tool use, and managed agents, and receives the OpenTelemetry traces that the Claude API exports.

## Add Anthropic as an AI provider

To use Anthropic models in the Braintrust playground, API, and gateway, connect Anthropic as a provider in your organization or project AI providers.

1. Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key.
2. Go to ** Settings** > [** Models**](https://www.braintrust.dev/app/~/configuration/models/organization).
3. Click  **Organization provider** to make the provider available across every project in the organization. To limit it to the current project, select the **Project** tab and click  **Project provider** instead.
4. Under **Model providers**, click **Anthropic**.
5. Choose your authentication method:
   * **API key**: Paste an Anthropic API key into the field below the authentication options.

     > [!NOTE]
     >
     > API keys are stored as one-way cryptographic hashes, never in plaintext.
   * **Workload identity federation**: Exchange a Braintrust-signed OIDC token for an Anthropic access token, instead of storing a long-lived Anthropic API key in Braintrust.

     > [!NOTE]
     >
     > Workload identity federation is available only for organization-level providers on Braintrust-hosted organizations with the Braintrust gateway enabled. Project-level providers and self-hosted deployments must use **API key** authentication.
6. If you chose **Workload identity federation**, use the setup values shown in Braintrust to configure Anthropic:

   1. Create an Anthropic service account. Copy the `svac_...` service account ID.
   2. Register the Braintrust issuer in Anthropic. Use the **Issuer URL** shown in Braintrust, set **JWKS source** to **OIDC discovery**, leave **Discovery base URL** blank, turn **Single-use tokens** on, and set **Max token lifetime** to **1 hour**.
   3. Create a federation rule in Anthropic. Use the **Subject pattern**, **Expected audience**, and **Required claims** shown in Braintrust. Select the service account from the previous step and the Anthropic workspace Braintrust should use.
   4. Paste the Anthropic IDs back into Braintrust:

   * **Federation rule ID**: The `fdrl_...` value in Anthropic's **Workload identity** > **Rules** table.
   * **Organization ID**: The ID shown on Anthropic's **Organization settings** > **Organization** page.
   * **Service account ID**: The `svac_...` ID from the Anthropic service account.
   * **Workspace ID**: Use `default` for Anthropic's default workspace, or the workspace ID selected in the federation rule.
   * **Subject suffix**: A stable suffix for this Anthropic connection. It must match the final part of the subject pattern used in Anthropic.

   For general Anthropic concepts and Console details, see [Anthropic's workload identity federation docs](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation).
7. Click **Create**, or **Update** when editing an existing provider.

**TypeScript**

## Tracing

Braintrust traces Anthropic calls automatically with the `braintrust/hook.mjs` import hook, or manually with `wrapAnthropic`. Either path produces the same spans.

Pick the tracing path that fits your application. Auto-instrumentation is the recommended path for most users.

> [tab] Auto-instrumentation
>
> ### Setup
>
> Install the Braintrust SDK alongside the Anthropic SDK, then configure your API keys.
>
> **1. Install packages**
>
> ```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> pnpm add braintrust @anthropic-ai/sdk
> ```
>
> ```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> npm install braintrust @anthropic-ai/sdk
> ```
>
> **2. Get an Anthropic API key**
>
> Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).
>
> **3. Set environment variables**
>
> ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ANTHROPIC_API_KEY=<your-anthropic-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>
> ```
>
> ### Trace your application
>
> To trace Anthropic calls without modifying your application code, run your app with Braintrust's import hook to patch `@anthropic-ai/sdk` at startup.
>
> ```javascript title="trace-anthropic-auto.js" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> import Anthropic from "@anthropic-ai/sdk";
> import { initLogger } from "braintrust";
>
> initLogger({
>   projectName: "My Project", // Replace with your project name
>   apiKey: process.env.BRAINTRUST_API_KEY,
> });
>
> const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
>
> const result = await client.messages.create({
>   model: "claude-sonnet-4-5-20250929",
>   max_tokens: 1024,
>   messages: [{ role: "user", content: "What is machine learning?" }],
> });
> ```
>
> Run with the import hook:
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> node --import braintrust/hook.mjs trace-anthropic-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 and run the compiled file with the import hook, or [run TypeScript directly](https://docs.braintrust.dev/instrument/trace-llm-calls.md#auto-instrumentation) with a TypeScript loader.
>
> > [!NOTE]
> >
> > If you're using a bundler, see [Trace LLM calls](https://docs.braintrust.dev/instrument/trace-llm-calls.md#auto-instrumentation) for plugin and loader setup.
>
> ### AWS Bedrock
>
> To trace Claude models on AWS Bedrock through Anthropic's [`@anthropic-ai/bedrock-sdk`](https://www.npmjs.com/package/@anthropic-ai/bedrock-sdk), create an `AnthropicBedrock` client and run with the import hook. The package is built on `@anthropic-ai/sdk`, so calls appear under `anthropic.messages.create` with `provider: "anthropic"` metadata, identical to the direct Anthropic SDK.
>
> ```javascript title="trace-anthropic-bedrock-auto.js" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> import { AnthropicBedrock } from "@anthropic-ai/bedrock-sdk";
> import { initLogger } from "braintrust";
>
> initLogger({
>   projectName: "My Project", // Replace with your project name
>   apiKey: process.env.BRAINTRUST_API_KEY,
> });
>
> // Resolves AWS credentials from the standard environment chain
> const client = new AnthropicBedrock();
>
> const result = await client.messages.create({
>   model: "anthropic.claude-3-5-sonnet-20241022-v2:0",
>   max_tokens: 1024,
>   messages: [{ role: "user", content: "What is machine learning?" }],
> });
> ```
>
> Run with the import hook:
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> node --import braintrust/hook.mjs trace-anthropic-bedrock-auto.js
> ```

> [tab] Manual instrumentation
>
> ### Setup
>
> Install the Braintrust SDK alongside the Anthropic SDK, then configure your API keys.
>
> **1. Install packages**
>
> ```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> pnpm add braintrust @anthropic-ai/sdk
> ```
>
> ```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> npm install braintrust @anthropic-ai/sdk
> ```
>
> **2. Get an Anthropic API key**
>
> Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).
>
> **3. Set environment variables**
>
> ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ANTHROPIC_API_KEY=<your-anthropic-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>
> ```
>
> ### Trace your application
>
> To trace Anthropic calls manually, wrap your client with `wrapAnthropic`. Once wrapped, every `messages.create` call (including streaming) emits a span.
>
> ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> import Anthropic from "@anthropic-ai/sdk";
> import { wrapAnthropic, initLogger } from "braintrust";
>
> // Initialize the Braintrust logger
> const logger = initLogger({
>   projectName: "My Project", // Your project name
>   apiKey: process.env.BRAINTRUST_API_KEY,
> });
>
> // Wrap the Anthropic client with the Braintrust logger
> const client = wrapAnthropic(
>   new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }),
> );
>
> // All API calls are automatically logged
> const result = await client.messages.create({
>   model: "claude-sonnet-4-5-20250929",
>   max_tokens: 1024,
>   messages: [{ role: "user", content: "What is machine learning?" }],
> });
> ```
>
> > [!TIP]
> >
> > For more control over tracing, learn how to [customize traces](https://docs.braintrust.dev/instrument/advanced-tracing.md).
>
> ### AWS Bedrock
>
> To trace Claude models on AWS Bedrock through Anthropic's [`@anthropic-ai/bedrock-sdk`](https://www.npmjs.com/package/@anthropic-ai/bedrock-sdk), wrap the `AnthropicBedrock` client with `wrapAnthropic`. The package is built on `@anthropic-ai/sdk`, so calls appear under `anthropic.messages.create` with `provider: "anthropic"` metadata, identical to the direct Anthropic SDK.
>
> ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> import { AnthropicBedrock } from "@anthropic-ai/bedrock-sdk";
> import { wrapAnthropic, initLogger } from "braintrust";
>
> initLogger({
>   projectName: "My Project", // Replace with your project name
>   apiKey: process.env.BRAINTRUST_API_KEY,
> });
>
> // Resolves AWS credentials from the standard environment chain
> const client = wrapAnthropic(new AnthropicBedrock());
>
> const result = await client.messages.create({
>   model: "anthropic.claude-3-5-sonnet-20241022-v2:0",
>   max_tokens: 1024,
>   messages: [{ role: "user", content: "What is machine learning?" }],
> });
> ```

> [!NOTE]
>
> To trace the native AWS Bedrock Runtime client (`@aws-sdk/client-bedrock-runtime`) instead, see [AWS Bedrock](https://docs.braintrust.dev/integrations/ai-providers/bedrock.md#tracing-typescript).

### Gateway

To call Anthropic through the [Braintrust gateway](https://docs.braintrust.dev/deploy/gateway.md), point an OpenAI-compatible client at the gateway base URL and use your Braintrust API key for authentication.

```typescript 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: "claude-sonnet-4-5-20250929",
  messages: [{ role: "user", content: "What is a gateway?" }],
  seed: 1, // A seed activates the gateway's cache
});
```

### Structured outputs

Anthropic supports structured outputs natively via the `output_config` parameter on the Anthropic SDK, or through the [Braintrust gateway](https://docs.braintrust.dev/deploy/gateway.md) using an OpenAI-shaped `response_format`.

```typescript Native Anthropic SDK theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import Anthropic from "@anthropic-ai/sdk";
import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";
import { z } from "zod";

const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

// Define a Zod schema for the response
const ResponseSchema = z.object({
  name: z.string(),
  age: z.number(),
});

const message = await client.messages.parse({
  model: "claude-sonnet-4-5-20250929",
  max_tokens: 1024,
  messages: [
    { role: "user", content: "My name is John and I'm 30 years old." },
  ],
  output_config: {
    format: zodOutputFormat(ResponseSchema),
  },
});

console.log(message.parsed_output); // { name: "John", age: 30 }
```

```typescript Via Braintrust gateway theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import { OpenAI } from "openai";
import { z } from "zod";

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

// Define a Zod schema for the response
const ResponseSchema = z.object({
  name: z.string(),
  age: z.number(),
});

const completion = await client.beta.chat.completions.parse({
  model: "claude-sonnet-4-5-20250929",
  messages: [
    { role: "system", content: "Extract the person's name and age." },
    { role: "user", content: "My name is John and I'm 30 years old." },
  ],
  response_format: {
    type: "json_schema",
    json_schema: {
      name: "person",
      // The Zod schema for the response
      schema: ResponseSchema,
    },
  },
});
```

### What Braintrust traces

Braintrust emits spans for the Anthropic SDK's messages API, beta tool runner, and beta sessions API. Message spans capture the input messages, system prompt, model, request parameters, response content, stop reason, and stop sequence. Beta tool-runner spans capture task input, tools, response messages, and aggregated metrics across iterations. Sessions spans capture the turn input, model, and response from `anthropic.beta.sessions.turn` and `anthropic.beta.sessions.thread.turn` calls.

**Spans**

| Span | Coverage |
| - | - |
| `anthropic.messages.create` | Messages API (and beta messages) |
| `anthropic.beta.messages.toolRunner` | Beta messages tool-runner iterations |
| `anthropic.beta.sessions.turn` | Beta sessions single-turn calls |
| `anthropic.beta.sessions.thread.turn` | Beta sessions thread-turn calls |

**Metrics**

| Metric | Description |
| - | - |
| `prompt_tokens` | Input tokens |
| `completion_tokens` | Output tokens |
| `prompt_cached_tokens` | Tokens read from the prompt cache |
| `prompt_cache_creation_tokens` | Tokens written to the prompt cache |
| `time_to_first_token` | First-token latency (streaming only) |
| `server_tool_use_*` | Server-side tool usage counters (for example, `server_tool_use_web_search_requests`) |

#### Collect sessions event streams

The `anthropic.beta.sessions.turn` and `anthropic.beta.sessions.thread.turn` spans are recorded automatically for non-streaming turns. When you consume a sessions event stream instead, call `collectAnthropicSession` on the stream to opt it into span collection. The client must be auto-instrumented or wrapped with `wrapAnthropic`, and `collectAnthropicSession` returns the same stream unchanged.

```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import Anthropic from "@anthropic-ai/sdk";
import { wrapAnthropic, collectAnthropicSession, initLogger } from "braintrust";

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

const client = wrapAnthropic(
  new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }),
);

// Open a sessions event stream. See the Anthropic Sessions API for parameters.
const stream = client.beta.sessions.events.stream({
  // Session request parameters
});

// Opt the stream into Braintrust span collection before consuming it
collectAnthropicSession(stream);

// The sessions span is recorded once the stream is fully consumed
for await (const event of stream) {
  // Handle each event
}
```

### Tracing resources

* [Braintrust JavaScript SDK](https://github.com/braintrustdata/braintrust-sdk-javascript)
* [Anthropic TypeScript SDK](https://github.com/anthropics/anthropic-sdk-typescript)
* [Anthropic Messages API reference](https://docs.anthropic.com/en/api/messages)
* [Prompt caching](https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching)

## Evals

Evaluations distill the non-deterministic outputs of Anthropic models into an effective feedback loop. The Braintrust `Eval` function is composed of a dataset of user inputs, a task, and a set of scorers. To learn more about evaluations, see the [Experiments](https://docs.braintrust.dev/evaluate/run-evaluations.md) guide.

### Basic eval setup

Evaluate the outputs of Anthropic models with Braintrust.

```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import { Eval } from "braintrust";
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

Eval("Anthropic Evaluation", {
  // An array of user inputs and expected outputs
  data: () => [
    { input: "What is 2+2?", expected: "4" },
    { input: "What is the capital of France?", expected: "Paris" },
  ],
  task: async (input) => {
    // Your Anthropic LLM call
    const response = await client.messages.create({
      model: "claude-sonnet-4-5-20250929",
      max_tokens: 1024,
      messages: [{ role: "user", content: input }],
    });
    return response.content[0].text;
  },
  scores: [
    {
      name: "accuracy",
      // A simple scorer that returns 1 if the output matches the expected output, 0 otherwise
      scorer: (args) => (args.output === args.expected ? 1 : 0),
    },
  ],
});
```

> [!TIP]
>
> Learn more about eval [data](https://docs.braintrust.dev/annotate/datasets.md) and [scorers](https://docs.braintrust.dev/evaluate/write-scorers.md).

### Use Anthropic as an LLM judge

You can use Anthropic models to score the outputs of other AI systems. This example uses the `LLMClassifierFromSpec` scorer to score the relevance of the outputs of an AI system.

Install the [`autoevals`](https://docs.braintrust.dev/evaluate/autoevals) package to use the `LLMClassifierFromSpec` scorer.

```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
pnpm add autoevals
```

```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
npm install autoevals
```

Create a scorer that uses the `LLMClassifierFromSpec` scorer to score the relevance of the output. You can then include `relevanceScorer` as a scorer in your `Eval` function (see above).

```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import { LLMClassifierFromSpec } from "autoevals";

const relevanceScorer = LLMClassifierFromSpec("Relevance", {
  choice_scores: { Relevant: 1, Irrelevant: 0 },
  model: "claude-sonnet-4-5-20250929",
  use_cot: true,
});
```

**Python**

## Tracing

Braintrust traces Anthropic calls automatically with `auto_instrument()`, or manually with `wrap_anthropic`. Either path produces the same spans.

Pick the tracing path that fits your application. Auto-instrumentation is the recommended path for most users.

> [tab] Auto-instrumentation
>
> ### Setup
>
> Install the Braintrust SDK alongside the Anthropic SDK, then configure your API keys.
>
> **1. Install packages**
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> pip install braintrust anthropic
> ```
>
> **2. Get an Anthropic API key**
>
> Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).
>
> **3. Set environment variables**
>
> ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ANTHROPIC_API_KEY=<your-anthropic-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>
> ```
>
> ### Trace your application
>
> To trace Anthropic calls without modifying your client construction, call `auto_instrument()` once at startup. Braintrust patches the `anthropic` SDK so every `messages.create`, `messages.stream`, `messages.parse`, beta messages, batches, and managed agents call emits a span.
>
> ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> import os
> import anthropic
> from braintrust import auto_instrument, init_logger
>
> init_logger(project="My Project")  # Replace with your project name
> auto_instrument()
>
> client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
>
> result = client.messages.create(
>     model="claude-sonnet-4-5-20250929",
>     max_tokens=1024,
>     messages=[{"role": "user", "content": "What is machine learning?"}],
> )
> ```

> [tab] Manual instrumentation
>
> ### Setup
>
> Install the Braintrust SDK alongside the Anthropic SDK, then configure your API keys.
>
> **1. Install packages**
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> pip install braintrust anthropic
> ```
>
> **2. Get an Anthropic API key**
>
> Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).
>
> **3. Set environment variables**
>
> ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ANTHROPIC_API_KEY=<your-anthropic-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>
> ```
>
> ### Trace your application
>
> To trace Anthropic calls manually, wrap your client with `wrap_anthropic`. Once wrapped, every `messages.create` call (including streaming) emits a span.
>
> ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> import os
>
> import anthropic
> from braintrust import init_logger, wrap_anthropic
>
> # Initialize the Braintrust logger
> logger = init_logger(project="My Project")
>
> # Wrap the Anthropic client with the Braintrust logger
> client = wrap_anthropic(anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"]))
>
> # All API calls are automatically logged
> result = client.messages.create(
>     model="claude-sonnet-4-5-20250929",
>     max_tokens=1024,
>     messages=[{"role": "user", "content": "What is machine learning?"}],
> )
> ```
>
> > [!TIP]
> >
> > For more control over tracing, learn how to [customize traces](https://docs.braintrust.dev/instrument/advanced-tracing.md).

### Gateway

To call Anthropic through the [Braintrust gateway](https://docs.braintrust.dev/deploy/gateway.md), point an OpenAI-compatible client at the gateway base URL and use your Braintrust API key for authentication.

```python 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="claude-sonnet-4-5-20250929",
    messages=[{"role": "user", "content": "What is a gateway?"}],
    seed=1,  # A seed activates the gateway's cache
)
```

### Structured outputs

Anthropic supports structured outputs natively via the `output_format` parameter on the Anthropic SDK, or through the [Braintrust gateway](https://docs.braintrust.dev/deploy/gateway.md) using an OpenAI-shaped `response_format`.

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

import anthropic
from pydantic import BaseModel

class Person(BaseModel):
    name: str
    age: int

client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

message = client.messages.parse(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "My name is John and I'm 30 years old."},
    ],
    output_format=Person,
)

print(message.content[0].parsed_output)  # Person(name="John", age=30)
```

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

from openai import OpenAI
from pydantic import BaseModel

class Person(BaseModel):
    name: str
    age: int

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

completion = client.beta.chat.completions.parse(
    model="claude-sonnet-4-5-20250929",
    messages=[
        {"role": "system", "content": "Extract the person's name and age."},
        {"role": "user", "content": "My name is John and I'm 30 years old."},
    ],
    response_format=Person,
)
```

### What Braintrust traces

Braintrust emits spans for the Anthropic SDK's messages, batches, and managed agents APIs, and for the beta tool runner and message threads. Messages spans capture the input messages, system prompt, response content, stop reason, stop sequence, stop details (such as refusal details), and request parameters (`model`, `max_tokens`, `temperature`, `speed`, `top_k`, `top_p`, `stop_sequences`, `tool_choice`, `tools`, `stream`, `thinking`, `output_config`, `output_format`, `compaction`, `context_management`, `diagnostics`).

A `client.beta.messages.tool_runner()` run, including one started from a message thread, creates an `anthropic.messages.tool_runner` task span with the input messages, tools, and final assistant message. Each model call in the run is a child LLM span, and each tool your code runs is a child `tool` span named after the tool, with its input and result. For a tool from a toolset, the `tool` span also records `toolset_name` and `tool_use_id` in metadata, and records an error when the tool result is an error. Calls made through `client.beta.messages.thread()` create standard messages spans that record the thread link in `metadata.thread`.

**Spans**

| Span | Coverage |
| - | - |
| `anthropic.messages.create`, `anthropic.messages.stream` | Messages API (and beta equivalents under `anthropic.beta.messages.*`) |
| `anthropic.messages.parse` | Structured output calls (captures `parsed_output` alongside standard message fields) |
| `anthropic.messages.batches.*` | Batches API |
| `anthropic.messages.tool_runner` | Beta tool runner runs, with child LLM and `tool` spans (Python SDK v0.48.1 or later) |
| `anthropic.beta.agents.*`, `anthropic.beta.sessions.*` | Managed agents and sessions |
| Server-side tool spans | One child `tool` span per server-side tool call (for example, web search) or MCP connector tool call in the response, named after the tool and capturing its input and result |

**Metrics**

| Metric | Description |
| - | - |
| `prompt_tokens` | Input tokens |
| `completion_tokens` | Output tokens |
| `prompt_cached_tokens` | Tokens read from the prompt cache |
| `prompt_cache_creation_tokens` | Tokens written to the prompt cache (aggregate) |
| `prompt_cache_creation_5m_tokens` | Tokens written to Anthropic's 5-minute ephemeral cache |
| `prompt_cache_creation_1h_tokens` | Tokens written to Anthropic's 1-hour ephemeral cache |
| `completion_reasoning_tokens` | Reasoning tokens produced by extended thinking (a subset of `completion_tokens`) |
| `time_to_first_token` | First-token latency (streaming only) |
| `server_tool_use_*` | Server-side tool usage counters (for example, `server_tool_use_web_search_requests`) |

**Metadata**

| Field | Description |
| - | - |
| `usage_service_tier` | Service tier that handled the request |
| `usage_inference_geo` | Region that processed the request |
| `usage_speed` | Inference speed mode used for the request (`standard` or `fast`) |
| `usage_fallback_credit` | Outcome of a `fallback_credit_token`, which Anthropic returns with a refusal so that a retry on a fallback model is billed at a reduced cache rate. Includes whether the credit was `redeemed` or `not_applied` |
| `cache_miss_reason` | Reason the prompt cache missed, such as `system_changed`. Present when you request prompt cache diagnostics by passing `diagnostics` with a `previous_message_id`, and Anthropic reports a cache miss in the response |
| `cache_missed_input_tokens` | Number of input tokens that missed the prompt cache, as reported with `cache_miss_reason` |
| `thread` | Message thread link for calls made through a message thread: `type` (such as `create` or `continue`) and, when continuing, `previous_message_id` |

### Tracing resources

* [Braintrust Python SDK](https://github.com/braintrustdata/braintrust-sdk-python)
* [Anthropic Python SDK](https://github.com/anthropics/anthropic-sdk-python)
* [Anthropic Messages API reference](https://docs.anthropic.com/en/api/messages)
* [Prompt caching](https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching)

## Evals

Evaluations distill the non-deterministic outputs of Anthropic models into an effective feedback loop. The Braintrust `Eval` function is composed of a dataset of user inputs, a task, and a set of scorers. To learn more about evaluations, see the [Experiments](https://docs.braintrust.dev/evaluate/run-evaluations.md) guide.

### Basic eval setup

Evaluate the outputs of Anthropic models with Braintrust.

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

import anthropic
from braintrust import Eval

client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

def task(input):
    response = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        messages=[{"role": "user", "content": input}],
    )
    return response.content[0].text

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

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

> [!TIP]
>
> Learn more about eval [data](https://docs.braintrust.dev/annotate/datasets.md) and [scorers](https://docs.braintrust.dev/evaluate/write-scorers.md).

### Use Anthropic as an LLM judge

You can use Anthropic models to score the outputs of other AI systems. This example uses the `LLMClassifierFromSpec` scorer to score the relevance of the outputs of an AI system.

Install the [`autoevals`](https://docs.braintrust.dev/evaluate/autoevals) package to use the `LLMClassifierFromSpec` scorer.

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

Create a scorer that uses the `LLMClassifierFromSpec` scorer to score the relevance of the output. You can then include `relevance_scorer` as a scorer in your `Eval` function (see above).

```python Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
from autoevals import LLMClassifierFromSpec

relevance_scorer = LLMClassifierFromSpec(
    "Relevance",
    choice_scores={"Relevant": 1, "Irrelevant": 0},
    model="claude-sonnet-4-5-20250929",
    use_cot=True,
)
```

**Ruby**

## Tracing

Braintrust traces Anthropic calls automatically when you load `braintrust/setup`, or manually with `Braintrust.instrument!`. Either path produces the same spans.

Pick the tracing path that fits your application. Auto-instrumentation is the recommended path for most users.

> [tab] Auto-instrumentation
>
> ### Setup
>
> Install the Braintrust gem alongside the Anthropic gem, then configure your API keys.
>
> **1. Install gems**
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> gem install braintrust anthropic
> ```
>
> **2. Get an Anthropic API key**
>
> Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).
>
> **3. Set environment variables**
>
> ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ANTHROPIC_API_KEY=<your-anthropic-api-key>
> BRAINTRUST_API_KEY=<your-braintrust-api-key>
> BRAINTRUST_DEFAULT_PROJECT=<your-project-name>  # Project that spans are logged to
>
> # 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>
> ```
>
> ### Trace your application
>
> To trace Anthropic calls without modifying your client construction, load `braintrust/setup` early in your application. Braintrust intercepts `require "anthropic"` and patches the gem so every `messages.create` and `messages.stream` call (including the beta messages API) emits a span.
>
> ```ruby Ruby theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> require 'braintrust/setup'
> require 'anthropic'
>
> client = Anthropic::Client.new(api_key: ENV.fetch('ANTHROPIC_API_KEY', nil))
>
> client.messages.create(
>   model: 'claude-sonnet-4-5-20250929',
>   max_tokens: 1024,
>   messages: [{ role: 'user', content: 'What is machine learning?' }]
> )
> ```
>
> > [!TIP]
> >
> > In a Rails app, add `gem "braintrust", require: "braintrust/setup"` to your Gemfile to enable auto-instrumentation without an explicit `require` line.

> [tab] Manual instrumentation
>
> ### Setup
>
> Install the Braintrust gem alongside the Anthropic gem, then configure your API keys.
>
> **1. Install gems**
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> gem install braintrust anthropic
> ```
>
> **2. Get an Anthropic API key**
>
> Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).
>
> **3. Set environment variables**
>
> ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ANTHROPIC_API_KEY=<your-anthropic-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>
> ```
>
> ### Trace your application
>
> To trace Anthropic calls manually, instrument your client with `Braintrust.instrument!`. Once instrumented, every `messages.create` call (including streaming) emits a span.
>
> ```ruby Ruby theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> require 'braintrust'
> require 'anthropic'
>
> # Initialize Braintrust
> Braintrust.init(default_project: 'My Project')
>
> # Create Anthropic client
> client = Anthropic::Client.new(api_key: ENV.fetch('ANTHROPIC_API_KEY', nil))
>
> # Instrument the client with Braintrust tracing
> Braintrust.instrument!(:anthropic, target: client)
>
> # All API calls are automatically logged
> client.messages.create(
>   model: 'claude-sonnet-4-5-20250929',
>   max_tokens: 1024,
>   messages: [{ role: 'user', content: 'What is machine learning?' }]
> )
> ```
>
> > [!TIP]
> >
> > For more control over tracing, learn how to [customize traces](https://docs.braintrust.dev/instrument/advanced-tracing.md).

### What Braintrust traces

Braintrust emits spans for the Anthropic SDK's messages API. Each span captures the input messages, system prompt, response content, stop reason, stop sequence, and request parameters (`model`, `max_tokens`, `temperature`, `top_p`, `top_k`, `stop_sequences`, `tools`, `tool_choice`, `thinking`, `metadata`, `service_tier`).

**Spans**

| Span | Coverage |
| - | - |
| `anthropic.messages.create`, `anthropic.messages.stream` | Messages API (and beta equivalents) |

**Metrics**

| Metric | Description |
| - | - |
| `prompt_tokens` | Input tokens |
| `completion_tokens` | Output tokens |
| `prompt_cached_tokens` | Tokens read from the prompt cache |
| `prompt_cache_creation_tokens` | Tokens written to the prompt cache |
| `time_to_first_token` | First-token latency (streaming only) |

### Tracing resources

* [Braintrust Ruby SDK](https://github.com/braintrustdata/braintrust-sdk-ruby)
* [Anthropic Ruby SDK](https://github.com/anthropics/anthropic-sdk-ruby)
* [Anthropic Messages API reference](https://docs.anthropic.com/en/api/messages)

## Evals

Evaluations distill the non-deterministic outputs of Anthropic models into an effective feedback loop. The Braintrust `Eval` API is composed of a dataset of user inputs, a task, and a set of scorers. To learn more about evaluations, see the [Experiments](https://docs.braintrust.dev/evaluate/run-evaluations.md) guide.

### Basic eval setup

Evaluate the outputs of Anthropic models with Braintrust.

```ruby Ruby theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
require 'braintrust'
require 'anthropic'

Braintrust.init

client = Anthropic::Client.new(api_key: ENV.fetch('ANTHROPIC_API_KEY', nil))

Braintrust::Eval.run(
  project: 'Anthropic Evaluation',
  experiment: 'basic-eval',
  # An array of user inputs and expected outputs
  cases: [
    { input: 'What is 2+2?', expected: '4' },
    { input: 'What is the capital of France?', expected: 'Paris' }
  ],
  # Your Anthropic LLM call
  task: lambda do |input|
    response = client.messages.create(
      model: 'claude-sonnet-4-5-20250929',
      max_tokens: 1024,
      messages: [{ role: 'user', content: input }]
      )
    response.content[0].text
  end,
  # A simple scorer that returns 1 if the output matches the expected output, 0 otherwise
  scorers: [
    Braintrust::Eval.scorer('accuracy') do |_input, expected, output|
      output == expected ? 1.0 : 0.0
    end
  ]
)
```

> [!TIP]
>
> Learn more about eval [data](https://docs.braintrust.dev/annotate/datasets.md) and [scorers](https://docs.braintrust.dev/evaluate/write-scorers.md).

**Go**

## Tracing

The Braintrust Go SDK ships an Anthropic middleware that you can attach manually, or apply automatically at compile time with [Orchestrion](https://github.com/DataDog/orchestrion). Either path produces the same traces.

Pick the tracing path that fits your application. Auto-instrumentation is the recommended path for most users.

> [tab] Auto-instrumentation
>
> ### Setup
>
> Install the Braintrust Go SDK alongside the Anthropic Go SDK, then configure your API keys.
>
> **1. 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/anthropic
> go get github.com/anthropics/anthropic-sdk-go
> ```
>
> **2. Get an Anthropic API key**
>
> Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).
>
> **3. Set environment variables**
>
> ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ANTHROPIC_API_KEY=<your-anthropic-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>
> ```
>
> ### Trace your application
>
> To trace Anthropic calls without modifying your application code, build your app with [Orchestrion](https://github.com/DataDog/orchestrion), a compile-time tool that rewrites every `anthropic.NewClient` call to attach Braintrust's middleware automatically.
>
> **1. Install Orchestrion**
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> go install github.com/DataDog/orchestrion@latest
> ```
>
> **2. Create orchestrion.tool.go in your project root**
>
> ```go title="orchestrion.tool.go" #skip-compile #skip-format 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/anthropic"
> )
> ```
>
> **3. Write your app**
>
> Orchestrion instruments every `anthropic.NewClient` call at build time, so no middleware wiring is needed.
>
> ```go Go #skip-compile #skip-format theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> package main
>
> import (
> 	"context"
> 	"log"
> 	"os"
>
> 	"github.com/anthropics/anthropic-sdk-go"
> 	"go.opentelemetry.io/otel"
> 	"go.opentelemetry.io/otel/sdk/trace"
>
> 	"github.com/braintrustdata/braintrust-sdk-go"
> )
>
> func main() {
> 	ctx := context.Background()
>
> 	tp := trace.NewTracerProvider()
> 	defer tp.Shutdown(ctx)
> 	otel.SetTracerProvider(tp)
>
> 	_, err := braintrust.New(tp,
> 		braintrust.WithProject("My Project"),
> 		braintrust.WithAPIKey(os.Getenv("BRAINTRUST_API_KEY")),
> 	)
> 	if err != nil {
> 		log.Fatal(err)
> 	}
>
> 	client := anthropic.NewClient()
>
> 	message, err := client.Messages.New(ctx, anthropic.MessageNewParams{
> 		Model: anthropic.ModelClaudeSonnet4_5_20250929,
> 		Messages: []anthropic.MessageParam{
> 			anthropic.NewUserMessage(anthropic.NewTextBlock("What is machine learning?")),
> 		},
> 		MaxTokens: 1024,
> 	})
> 	if err != nil {
> 		log.Fatal(err)
> 	}
> 	_ = message
> }
> ```
>
> **4. Build and run with Orchestrion**
>
> Build with Orchestrion to enable auto-instrumentation:
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> go mod tidy
> orchestrion go build -o myapp
> ./myapp
> ```
>
> > [accordion] Enable Orchestrion via GOFLAGS
> >
> > Instead of running `orchestrion go build`, you can set a `GOFLAGS` environment variable to enable Orchestrion for normal `go build` commands:
> >
> > ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> > export GOFLAGS="-toolexec='orchestrion toolexec'"
> > go build ./...
> > ```

> [tab] Manual instrumentation
>
> ### Setup
>
> Install the Braintrust Go SDK alongside the Anthropic Go SDK, then configure your API keys.
>
> **1. 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/anthropic
> go get github.com/anthropics/anthropic-sdk-go
> ```
>
> **2. Get an Anthropic API key**
>
> Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).
>
> **3. Set environment variables**
>
> ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ANTHROPIC_API_KEY=<your-anthropic-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>
> ```
>
> ### Trace your application
>
> To trace Anthropic calls manually, attach Braintrust's tracing middleware yourself by passing `traceanthropic.NewMiddleware()` as an option on `anthropic.NewClient`. Once attached, every `Messages.New` call (including streaming) emits a span.
>
> ```go Go theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> package main
>
> import (
> 	"context"
> 	"log"
> 	"os"
>
> 	"github.com/anthropics/anthropic-sdk-go"
> 	"github.com/anthropics/anthropic-sdk-go/option"
> 	"go.opentelemetry.io/otel"
> 	"go.opentelemetry.io/otel/sdk/trace"
>
> 	"github.com/braintrustdata/braintrust-sdk-go"
> 	traceanthropic "github.com/braintrustdata/braintrust-sdk-go/trace/contrib/anthropic"
> )
>
> func main() {
> 	ctx := context.Background()
>
> 	// Set up OpenTelemetry TracerProvider
> 	tp := trace.NewTracerProvider()
> 	defer tp.Shutdown(ctx)
> 	otel.SetTracerProvider(tp)
>
> 	// Initialize Braintrust client
> 	_, err := braintrust.New(tp,
> 		braintrust.WithProject("My Project"),
> 		braintrust.WithAPIKey(os.Getenv("BRAINTRUST_API_KEY")),
> 	)
> 	if err != nil {
> 		log.Fatal(err)
> 	}
>
> 	// Create Anthropic client with tracing middleware
> 	client := anthropic.NewClient(
> 		option.WithMiddleware(traceanthropic.NewMiddleware()),
> 	)
>
> 	// All API calls are automatically logged
> 	message, err := client.Messages.New(ctx, anthropic.MessageNewParams{
> 		Model: anthropic.ModelClaudeSonnet4_5_20250929,
> 		Messages: []anthropic.MessageParam{
> 			anthropic.NewUserMessage(anthropic.NewTextBlock("What is machine learning?")),
> 		},
> 		MaxTokens: 1024,
> 	})
> 	if err != nil {
> 		log.Fatal(err)
> 	}
> 	_ = message
> }
> ```
>
> > [!TIP]
> >
> > For more control over tracing, learn how to [customize traces](https://docs.braintrust.dev/instrument/advanced-tracing.md).

### What Braintrust traces

Braintrust emits spans for the Anthropic SDK's messages API. Each span captures the input messages, system prompt, response content, and request parameters (`model`, `max_tokens`, `temperature`, `top_p`, `top_k`, `stop_sequences`, `stream`, `tools`, `tool_choice`, `metadata`, `container`, `mcp_servers`, `service_tier`, `thinking`, `context_management`).

**Spans**

| Span | Coverage |
| - | - |
| `anthropic.messages.create` | `/v1/messages` requests |

**Metrics**

| Metric | Description |
| - | - |
| `prompt_tokens` | Input tokens |
| `completion_tokens` | Output tokens |
| `prompt_cached_tokens` | Tokens read from the prompt cache |
| `prompt_cache_creation_tokens` | Tokens written to the prompt cache (aggregate) |
| `prompt_cache_creation_5m_tokens` | Tokens written to Anthropic's 5-minute ephemeral cache |
| `prompt_cache_creation_1h_tokens` | Tokens written to Anthropic's 1-hour ephemeral cache |
| `time_to_first_token` | First-token latency (streaming only) |

**Metadata**

| Field | Description |
| - | - |
| `context_management` | Merges the request-side `context_management` config with the `applied_edits` reported in the response. Requires the `context-management-2025-06-27` Anthropic beta header. |

### Tracing resources

* [Braintrust Go SDK](https://github.com/braintrustdata/braintrust-sdk-go)
* [Anthropic Go SDK](https://github.com/anthropics/anthropic-sdk-go)
* [Anthropic Messages API reference](https://docs.anthropic.com/en/api/messages)

## Evals

Evaluations distill the non-deterministic outputs of Anthropic models into an effective feedback loop. The Braintrust `Evaluator` API is composed of a dataset of user inputs, a task, and a set of scorers. To learn more about evaluations, see the [Experiments](https://docs.braintrust.dev/evaluate/run-evaluations.md) guide.

### Basic eval setup

Evaluate the outputs of Anthropic models with Braintrust.

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

import (
	"context"
	"log"
	"os"

	"github.com/anthropics/anthropic-sdk-go"
	"github.com/anthropics/anthropic-sdk-go/option"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/sdk/trace"

	"github.com/braintrustdata/braintrust-sdk-go"
	"github.com/braintrustdata/braintrust-sdk-go/eval"
	traceanthropic "github.com/braintrustdata/braintrust-sdk-go/trace/contrib/anthropic"
)

func main() {
	ctx := context.Background()

	// Set up OpenTelemetry TracerProvider
	tp := trace.NewTracerProvider()
	defer tp.Shutdown(ctx)
	otel.SetTracerProvider(tp)

	// Initialize Braintrust
	bt, err := braintrust.New(tp,
		braintrust.WithAPIKey(os.Getenv("BRAINTRUST_API_KEY")),
	)
	if err != nil {
		log.Fatal(err)
	}

	// Create Anthropic client with tracing
	client := anthropic.NewClient(
		option.WithMiddleware(traceanthropic.NewMiddleware()),
	)

	// Create evaluator
	evaluator := braintrust.NewEvaluator[string, string](bt)

	// Run evaluation
	_, err = evaluator.Run(ctx, eval.Opts[string, string]{
		Experiment: "Anthropic Evaluation",
		// Dataset of user inputs and expected outputs
		Dataset: eval.NewDataset([]eval.Case[string, string]{
			{Input: "What is 2+2?", Expected: "4"},
			{Input: "What is the capital of France?", Expected: "Paris"},
		}),
		// Task function with Anthropic LLM call
		Task: eval.T(func(ctx context.Context, input string) (string, error) {
			message, err := client.Messages.New(ctx, anthropic.MessageNewParams{
				Model: anthropic.ModelClaudeSonnet4_5_20250929,
				Messages: []anthropic.MessageParam{
					anthropic.NewUserMessage(anthropic.NewTextBlock(input)),
				},
				MaxTokens: 1024,
			})
			if err != nil {
				return "", err
			}
			return message.Content[0].Text, nil
		}),
		// Simple scorer that returns 1 if output matches expected, 0 otherwise
		Scorers: []eval.Scorer[string, string]{
			eval.NewScorer("accuracy", func(ctx context.Context, r eval.TaskResult[string, string]) (eval.Scores, error) {
				score := 0.0
				if r.Output == r.Expected {
					score = 1.0
				}
				return eval.S(score), nil
			}),
		},
	})
	if err != nil {
		log.Fatal(err)
	}
}
```

> [!TIP]
>
> Learn more about eval [data](https://docs.braintrust.dev/annotate/datasets.md) and [scorers](https://docs.braintrust.dev/evaluate/write-scorers.md).

**Java**

## Tracing

The Braintrust Java SDK ships an Anthropic interceptor that you can attach manually with `BraintrustAnthropic.wrap()`, or have applied automatically by the [Braintrust Java agent](https://docs.braintrust.dev/instrument/trace-llm-calls.md#auto-instrumentation). Both paths produce the same spans.

Pick the tracing path that fits your application. Auto-instrumentation is the recommended path for most users.

> [tab] Auto-instrumentation
>
> ### Setup
>
> Install the Braintrust Java SDK alongside the Anthropic Java SDK, then configure your API keys.
>
> **1. Install packages**
>
> ```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.anthropic:anthropic-java:<version-goes-here>'
> ```
>
> **2. Get an Anthropic API key**
>
> Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).
>
> **3. Set environment variables**
>
> ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ANTHROPIC_API_KEY=<your-anthropic-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>
> ```
>
> ### Trace your application
>
> To trace Anthropic calls without modifying your application code, attach the [`braintrust-java-agent`](https://docs.braintrust.dev/instrument/trace-llm-calls#auto-instrumentation) at JVM startup. The agent intercepts every Anthropic client build and applies the Braintrust interceptor automatically.
>
> **1. 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}"
> }
> ```
>
> **2. Run your app**
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ./gradlew run
> ```
>
> Anthropic client builds in your application code are now intercepted automatically. No call to `BraintrustAnthropic.wrap()` is required.
>
> > [!NOTE]
> >
> > The agent instruments both synchronous and asynchronous client builds, so `AnthropicOkHttpClient` and `AnthropicOkHttpClientAsync` clients are traced automatically.

> [tab] Manual instrumentation
>
> ### Setup
>
> Install the Braintrust Java SDK alongside the Anthropic Java SDK, then configure your API keys.
>
> **1. Install packages**
>
> ```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.anthropic:anthropic-java:<version-goes-here>'
> ```
>
> **2. Get an Anthropic API key**
>
> Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).
>
> **3. Set environment variables**
>
> ```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> ANTHROPIC_API_KEY=<your-anthropic-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>
> ```
>
> ### Trace your application
>
> To trace Anthropic calls manually, wrap your client with `BraintrustAnthropic.wrap()`. Once wrapped, every `messages().create()` call (including streaming) emits a span.
>
> ```java Java theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> import com.anthropic.client.AnthropicClient;
> import com.anthropic.client.okhttp.AnthropicOkHttpClient;
> import com.anthropic.models.messages.MessageCreateParams;
> import com.anthropic.models.messages.Model;
> import dev.braintrust.Braintrust;
> import dev.braintrust.instrumentation.anthropic.BraintrustAnthropic;
>
> class AnthropicTracing {
>     public static void main(String[] args) {
>         var braintrust = Braintrust.get();
>         var openTelemetry = braintrust.openTelemetryCreate();
>
>         // Wrap the Anthropic client with Braintrust instrumentation
>         AnthropicClient client = BraintrustAnthropic.wrap(openTelemetry, AnthropicOkHttpClient.fromEnv());
>
>         // All API calls are automatically logged
>         var result = client.messages().create(
>             MessageCreateParams.builder()
>                 .model(Model.CLAUDE_SONNET_4_5_20250929)
>                 .maxTokens(1024)
>                 .addUserMessage("What is machine learning?")
>                 .build());
>     }
> }
> ```
>
> > [!NOTE]
> >
> > To trace an asynchronous client, build it with `AnthropicOkHttpClientAsync` and wrap it the same way, importing `BraintrustAnthropic` from `dev.braintrust.instrumentation.anthropic.v2_2_0`.
>
> > [!TIP]
> >
> > For more control over tracing, learn how to [customize traces](https://docs.braintrust.dev/instrument/advanced-tracing.md).

### What Braintrust traces

Braintrust emits spans for the Anthropic Messages API. Each span captures the input messages and response content. Server-side tool calls (such as web search) appear as child `tool` spans nested under the LLM span.

**Spans**

| Span | Coverage |
| - | - |
| Anthropic Messages API spans | `messages().create()` calls, including streaming |
| Server-side tool spans | One child span per server-side tool call (for example, web search) reported in the response |

**Metrics**

| Metric | Description |
| - | - |
| `prompt_tokens` | Input tokens |
| `completion_tokens` | Output tokens |
| `prompt_cached_tokens` | Tokens read from the prompt cache |
| `prompt_cache_creation_tokens` | Tokens written to the prompt cache (aggregate) |
| `prompt_cache_creation_5m_tokens` | Tokens written to Anthropic's 5-minute ephemeral cache |
| `prompt_cache_creation_1h_tokens` | Tokens written to Anthropic's 1-hour ephemeral cache |
| `time_to_first_token` | First-token latency (streaming only) |
| `server_tool_use_*` | Server-side tool usage counters (for example, `server_tool_use_web_search_requests`) |

### Tracing resources

* [Braintrust Java SDK](https://github.com/braintrustdata/braintrust-sdk-java)
* [Trace LLM calls](https://docs.braintrust.dev/instrument/trace-llm-calls.md) for general Java agent setup
* [Anthropic Java SDK](https://github.com/anthropics/anthropic-sdk-java)
* [Anthropic Messages API reference](https://docs.anthropic.com/en/api/messages)

## Evals

Evaluations distill the non-deterministic outputs of Anthropic models into an effective feedback loop. To learn more about evaluations, see the [Experiments](https://docs.braintrust.dev/evaluate/run-evaluations.md) guide.

### Basic eval setup

Evaluate the outputs of Anthropic models with Braintrust.

```java Java theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
import dev.braintrust.Braintrust;
import dev.braintrust.eval.DatasetCase;
import dev.braintrust.eval.Scorer;
import dev.braintrust.instrumentation.anthropic.BraintrustAnthropic;
import java.util.function.Function;

class AnthropicEvaluation {
    public static void main(String[] args) {
        var braintrust = Braintrust.get();
        var openTelemetry = braintrust.openTelemetryCreate();
        AnthropicClient client = BraintrustAnthropic.wrap(openTelemetry, AnthropicOkHttpClient.fromEnv());

        Function<String, String> taskFunction = (String input) -> {
            var request = MessageCreateParams.builder()
                .model(Model.CLAUDE_SONNET_4_5_20250929)
                .maxTokens(1024)
                .addUserMessage(input)
                .build();
            var response = client.messages().create(request);
            return response.content().get(0).text().map(block -> block.text()).orElse("");
        };

        var eval = braintrust.<String, String>evalBuilder()
            .name("Anthropic Evaluation")
            .cases(
                DatasetCase.of("What is 2+2?", "4"),
                DatasetCase.of("What is the capital of France?", "Paris"))
            .taskFunction(taskFunction)
            .scorers(
                Scorer.of("contains_answer", (evalCase, output) ->
                    output.contains("4") || output.contains("Paris") ? 1.0 : 0.0))
            .build();

        var result = eval.run();
        System.out.println(result.createReportString());
    }
}
```

> [!TIP]
>
> Learn more about eval [data](https://docs.braintrust.dev/annotate/datasets.md) and [scorers](https://docs.braintrust.dev/evaluate/write-scorers.md).

**.NET**

## Tracing

The Braintrust .NET SDK ships an Anthropic instrumentation that you attach with the `.WithBraintrust()` extension method.

### Setup

Install the Braintrust .NET SDK alongside the Anthropic .NET SDK, then configure your API keys.

**1. Install packages**

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
# add to .csproj file
dotnet add package Braintrust.Sdk
dotnet add package Braintrust.Sdk.Anthropic
```

**2. Get an Anthropic API key**

Visit [Anthropic's Console](https://console.anthropic.com/settings/keys) and create a new API key, then [add it as a Braintrust AI provider](#add-anthropic-as-an-ai-provider).

**3. Set environment variables**

```bash title=".env" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
ANTHROPIC_API_KEY=<your-anthropic-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>
```

### Manual instrumentation

To trace Anthropic calls, wrap your client with `.WithBraintrust()`. Once wrapped, every `Messages.Create` call (including streaming) emits a span.

```csharp C# theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Anthropic;
using Anthropic.Models.Messages;
using Braintrust.Sdk.Anthropic;

class AnthropicTracing
{
    static async Task Main(string[] args)
    {
        // Wrap the Anthropic client with Braintrust instrumentation
        var client = new AnthropicClient().WithBraintrust();

        // All API calls are automatically logged
        var result = await client.Messages.Create(new MessageCreateParams
        {
            Model = "claude-sonnet-4-5-20250929",
            MaxTokens = 1024,
            Messages = new List<MessageParam>
            {
                new MessageParam { Role = "user", Content = "What is machine learning?" }
            }
        });

        if (result.Content[0].TryPickText(out var textBlock))
        {
            Console.WriteLine(textBlock.Text);
        }
    }
}
```

> [!TIP]
>
> For more control over tracing, learn how to [customize traces](https://docs.braintrust.dev/instrument/advanced-tracing.md).

### What Braintrust traces

Braintrust emits spans for the Anthropic Messages API. Each span captures the input messages (including the system prompt), response content, model, and stop reason and stop sequence (streaming only). Request parameters such as max tokens, temperature, top-p, top-k, stop sequences, and tools are captured as metadata.

**Spans**

| Span | Coverage |
| - | - |
| `anthropic.messages.create` | Non-streaming messages calls |
| `Message Stream` | Streaming messages calls |

**Metrics**

| Metric | Description |
| - | - |
| `prompt_tokens` | Input tokens |
| `completion_tokens` | Output tokens |
| `tokens` | Total tokens |
| `time_to_first_token` | First-token latency (streaming only) |

### Tracing resources

* [Braintrust .NET SDK](https://github.com/braintrustdata/braintrust-sdk-dotnet)
* [Braintrust.Sdk.Anthropic](https://www.nuget.org/packages/Braintrust.Sdk.Anthropic)
* [Anthropic .NET SDK](https://github.com/anthropics/anthropic-sdk-dotnet)
* [Anthropic Messages API reference](https://docs.anthropic.com/en/api/messages)

## Export OpenTelemetry traces from the Claude API

The Claude API can [export OpenTelemetry traces](https://platform.claude.com/docs/en/manage-claude/opentelemetry) (now in public beta) of your Messages API requests and Claude Managed Agents sessions directly to Braintrust's OTLP endpoint. Anthropic sends these spans from its servers, so they include work your application can't observe, such as each model request, server tool use, compaction, and Managed Agents turn. No Braintrust SDK is required.

### Add Braintrust as a destination

You need an admin role in your Claude Console organization.

**1. Add a destination**

A destination is an [OTLP trace exporter](https://docs.braintrust.dev/integrations/sdk-integrations/opentelemetry/send-traces-and-logs.md#otlp-trace-exporter) that Anthropic runs for you. In the Claude Console, open the [OpenTelemetry settings page](https://platform.claude.com/settings/telemetry-destinations) and click **Add destination**.

Set **Provider** to **Braintrust** and fill in the form:

| Field | Value |
| - | - |
| **Region** | Your organization's [data plane region](https://docs.braintrust.dev/admin/organizations.md#data-plane-region) |
| **API key** | A [Braintrust API key](https://www.braintrust.dev/app/~/configuration/api-keys) |
| **Project ID** | The ID of the project to send traces to. To find it, go to your project's configuration page and click **Copy Project ID** at the bottom of the page. |
| **Content mode** | **Full content** to see prompts and responses in Braintrust, or **Metadata only** for timing, status, and token counts |

If your organization has a HIPAA, FERPA, or K-12 data-handling restriction with Anthropic, destinations export only metadata whatever their content mode.

> [accordion] Send traces to a self-hosted deployment
>
> If you're self-hosting Braintrust, set **Provider** to **Custom** and enter:
>
> | Field | Value |
> | - | - |
> | **OTLP endpoint URL** | Your stack's Universal API URL followed by `/otel` |
> | **Request headers** | `Authorization`: `Bearer <Your API Key>` `x-bt-parent`: `project_id:<Your Project ID>` |
>
> Anthropic appends `/v1/traces` to the endpoint URL and delivers only to a public hostname over HTTPS on port 443.
>
> The `x-bt-parent` header sets the trace's parent project or experiment. You can use a prefix like `project_id:`, `project_name:`, or `experiment_id:` here.
>
> **Custom** destinations default to a **Maximum content size** of 0.75 MB per span. When a span's content is larger, Anthropic shortens it and sets `anthropic.content.truncated` to `true`.

**2. Choose which workspaces export**

Set **Workspaces** to **All** to export spans from every workspace, **Selected** to export from only the workspaces you pick, or **All except** to export from every workspace except the ones you pick. To send different workspaces to different Braintrust projects, create one destination for each project.

**3. Verify delivery**

Send a Messages API request or run a Managed Agents session in a workspace that uses the destination. Confirm that the **Delivery** column in the Claude Console shows **Healthy**, then find the trace on the [\*\* Logs\*\*](https://www.braintrust.dev/app/~/logs) page of your project. Spans from the Claude API have `service.name` set to `claude-platform`.

If delivery shows **Failing** with status `401` or `403`, check the **API key** and **Project ID**.

### What Braintrust traces

Braintrust maps the Claude API spans with the [GenAI semantic conventions](https://docs.braintrust.dev/integrations/sdk-integrations/opentelemetry/attributes.md):

* Model request spans become LLM spans with the model and token metrics, so Braintrust can estimate cost.
* Tool spans become tool spans named after the tool.
* With **Full content**, the system prompt, input messages, and output messages of `anthropic.messages.create` and `anthropic.session.turn` spans become the span input and output, and tool arguments become the input of tool spans.
* `gen_ai.conversation.id`, which holds the Managed Agents session thread ID, is stored with the span. Other attributes, such as `anthropic.session.id`, are stored as metadata.

> [!WARNING]
>
> Trace-level token counts and estimated cost add up the metrics of every span in the trace. For a Messages API request, the `anthropic.messages.create` span and its `anthropic.model_request` spans report the same tokens, so trace totals count them twice. If your application also sends its Anthropic SDK spans to the same project, those spans report the same tokens again. The Claude API spans of a Managed Agents session report each token once.
>
> To count each token once, sum only the `anthropic.model_request`, `anthropic.compaction`, and `anthropic.session.outcome_evaluation` spans:
>
> ```sql theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
> SELECT
>   SUM(metrics.prompt_tokens) AS prompt_tokens,
>   SUM(metrics.completion_tokens) AS completion_tokens,
>   SUM(estimated_cost()) AS estimated_cost
> FROM project_logs('<PROJECT_ID>') -- Replace with your project ID
> WHERE root_span_id = '<ROOT_SPAN_ID>' -- Replace with the trace's root span ID
>   AND span_attributes.name IN ('anthropic.model_request', 'anthropic.compaction', 'anthropic.session.outcome_evaluation')
> ```

### Connect Claude API spans to your application's traces

By default, the spans of each request or session form their own trace. To nest them under your application's spans, pass a W3C `traceparent` header on your Claude API requests. The [Claude SDK](https://platform.claude.com/docs/en/manage-claude/opentelemetry/sdk) does this automatically when you call it inside an active OpenTelemetry span.

When the Claude API spans join your trace, their root is your application's span. Send your application's spans to the same Braintrust project, either with an [OTLP exporter](https://docs.braintrust.dev/integrations/sdk-integrations/opentelemetry/send-traces-and-logs.md#otlp-trace-exporter) or a [Braintrust span processor](https://docs.braintrust.dev/integrations/sdk-integrations/opentelemetry/send-traces-and-logs.md#braintrust-span-processor). Otherwise, the trace has no root span and doesn't appear on the **Logs** page.


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