> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://respan.ai/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://respan.ai/_mcp/server.

# Anthropic SDK (tracing)

> Trace Anthropic SDK calls with Respan — auto-instrumented spans, gateway routing, and full observability.

The [Anthropic SDK](https://github.com/anthropics/anthropic-sdk-python) is the official client for Anthropic's Claude models, supporting messages, streaming, and tool use. Respan gives you full observability over every Claude call, streamed response, and tool invocation — and gateway routing through the Anthropic-compatible Respan endpoint.

#### Set up Respan

Create an account at [platform.respan.ai](https://platform.respan.ai) and grab an [API key](https://platform.respan.ai/platform/api/api-keys).

Run `npx @respan/cli setup` to set up with your coding agent.

#### Use Respan Gateway

See [Anthropic SDK gateway setup](/docs/gateway/anthropic) to route this integration through the Respan gateway.

#### Example projects

* [Python examples](https://github.com/respanai/respan-example-projects/tree/main/python/tracing/anthropic)
* [TypeScript examples](https://github.com/respanai/respan-example-projects/tree/main/typescript/tracing/anthropic)

## Setup

#### Install packages

```bash Python
pip install respan-ai respan-instrumentation-anthropic anthropic
```

```bash TypeScript
npm install @respan/respan @respan/instrumentation-anthropic @anthropic-ai/sdk
```

#### Set environment variables

```bash
export ANTHROPIC_API_KEY="YOUR_ANTHROPIC_API_KEY"
export RESPAN_API_KEY="YOUR_RESPAN_API_KEY"
```

`ANTHROPIC_API_KEY` is used for Claude requests. `RESPAN_API_KEY` is used to export traces to Respan.

#### Initialize and run

```python Python
from anthropic import Anthropic
from respan import Respan
from respan_instrumentation_anthropic import AnthropicInstrumentor

respan = Respan(instrumentations=[AnthropicInstrumentor()])

client = Anthropic()

message = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Say hello in three languages."}],
)
print(message.content[0].text)
```

```typescript TypeScript
import Anthropic from "@anthropic-ai/sdk";
import { Respan } from "@respan/respan";
import { AnthropicInstrumentor } from "@respan/instrumentation-anthropic";

const respan = new Respan({
  apiKey: process.env.RESPAN_API_KEY,
  baseURL: process.env.RESPAN_BASE_URL,
  instrumentations: [new AnthropicInstrumentor()],
});
await respan.initialize();

const client = new Anthropic();

const message = await client.messages.create({
  model: "claude-sonnet-4-5-20250929",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Say hello in three languages." }],
});
console.log(message.content[0].type === "text" ? message.content[0].text : "");
```

#### View your trace

Open the [Traces page](https://platform.respan.ai/platform/traces) to see your auto-instrumented LLM spans with messages, tokens, and tool calls.

## Configuration

| Parameter             | Type           | Default | Description                                                           |
| --------------------- | -------------- | ------- | --------------------------------------------------------------------- |
| `api_key`             | `str \| None`  | `None`  | Falls back to `RESPAN_API_KEY` env var.                               |
| `base_url`            | `str \| None`  | `None`  | Falls back to `RESPAN_BASE_URL` env var.                              |
| `instrumentations`    | `list`         | `[]`    | Plugin instrumentations to activate (e.g. `AnthropicInstrumentor()`). |
| `customer_identifier` | `str \| None`  | `None`  | Default customer identifier for all spans.                            |
| `metadata`            | `dict \| None` | `None`  | Default metadata attached to all spans.                               |
| `environment`         | `str \| None`  | `None`  | Environment tag (e.g. `"production"`).                                |

## Attributes

### In Respan()

Set defaults at initialization — these apply to all spans.

```python Python
from respan import Respan
from respan_instrumentation_anthropic import AnthropicInstrumentor

respan = Respan(
    instrumentations=[AnthropicInstrumentor()],
    customer_identifier="user_123",
    metadata={"service": "chat-api", "version": "1.0.0"},
)
```

```typescript TypeScript
import { Respan } from "@respan/respan";
import { AnthropicInstrumentor } from "@respan/instrumentation-anthropic";

// Note: default attributes are set via propagateAttributes() in TypeScript
const respan = new Respan({
  instrumentations: [new AnthropicInstrumentor()],
});
```

### With propagate\_attributes

Override per-request using a context scope.

```python Python
from anthropic import Anthropic
from respan import Respan, propagate_attributes
from respan_instrumentation_anthropic import AnthropicInstrumentor

respan = Respan(instrumentations=[AnthropicInstrumentor()])
client = Anthropic()

def handle_request(user_id: str, question: str):
    with propagate_attributes(
        customer_identifier=user_id,
        thread_identifier="conv_abc_123",
        metadata={"plan": "pro"},
    ):
        message = client.messages.create(
            model="claude-sonnet-4-5-20250929",
            max_tokens=1024,
            messages=[{"role": "user", "content": question}],
        )
        print(message.content[0].text)
```

```typescript TypeScript
import Anthropic from "@anthropic-ai/sdk";
import { Respan } from "@respan/respan";
import { AnthropicInstrumentor } from "@respan/instrumentation-anthropic";

const respan = new Respan({
  instrumentations: [new AnthropicInstrumentor()],
});
await respan.initialize();

const client = new Anthropic();

async function handleRequest(userId: string, question: string) {
  await respan.propagateAttributes(
    {
      customer_identifier: userId,
      thread_identifier: "conv_abc_123",
      metadata: { plan: "pro" },
    },
    async () => {
      const message = await client.messages.create({
        model: "claude-sonnet-4-5-20250929",
        max_tokens: 1024,
        messages: [{ role: "user", content: question }],
      });
      console.log(message.content[0].type === "text" ? message.content[0].text : "");
    }
  );
}
```

| Attribute             | Type   | Description                                           |
| --------------------- | ------ | ----------------------------------------------------- |
| `customer_identifier` | `str`  | Identifies the end user in Respan analytics.          |
| `thread_identifier`   | `str`  | Groups related messages into a conversation.          |
| `metadata`            | `dict` | Custom key-value pairs. Merged with default metadata. |

## Decorators (optional)

Decorators are not required. All Anthropic calls are auto-traced by the instrumentor. Use `@workflow` and `@task` to add structure when you want to group related calls into a named workflow with nested tasks.

```python
from anthropic import Anthropic
from respan import Respan, workflow, task
from respan_instrumentation_anthropic import AnthropicInstrumentor

respan = Respan(instrumentations=[AnthropicInstrumentor()])
client = Anthropic()

@task(name="generate_outline")
def outline(topic: str) -> str:
    message = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        messages=[{"role": "user", "content": f"Create a brief outline about: {topic}"}],
    )
    return message.content[0].text

@workflow(name="content_pipeline")
def pipeline(topic: str):
    plan = outline(topic)
    message = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=2048,
        messages=[{"role": "user", "content": f"Write content from this outline: {plan}"}],
    )
    print(message.content[0].text)

pipeline("Benefits of API gateways")
```

## Examples

### Streaming

Stream Claude responses with real-time text deltas.

```python
with client.messages.stream(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a haiku about Python."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
```

### Tool calls

Tool calls are automatically captured as spans with inputs, outputs, and timing.

```python
tools = [
    {
        "name": "get_weather",
        "description": "Get the weather for a city.",
        "input_schema": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    }
]

message = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "What's the weather in Paris?"}],
)
```