- Two independent halves: API spans (emitted by Anthropic, delivered to a destination you register) and SDK spans (emitted by the
anthropicpackage in your process). - Only an organization admin can add a destination. Developers can view them.[1]
- The destination content mode and the SDK content mode are separate settings. The SDK setting has no effect on API spans.[3]
- Delivery is at least once and best effort. Do not build billing from spans; use the Usage and Cost API.
- Up to 10 destinations per organization, HTTPS on port 443, a hostname rather than an IP, and no
/v1/tracessuffix in the base URL. - Claude Code and Agent SDK telemetry is a different system with different environment variables.
Since 14 October 2026 the Claude API can send one OpenTelemetry trace per request or Managed Agents session to the observability backend you already run, and the first thing to decide is the destination's content mode: Metadata only or Full content.[4] Metadata only exports identifiers, timing, status and token counts. Full content also exports prompts and responses, and they then live under your backend's retention rules, not Anthropic's.[2] The feature is in public beta. An organization admin adds a destination in the Claude Console, you need no code changes for the server-side half, and an optional SDK half adds client spans that join the same trace. This post covers what each half does, the exact Console fields, a Honeycomb walk-through, the span names worth knowing, and what the docs say about limits and delivery.
What you get: server-side spans and client-side spans
Anthropic describes the feature as OpenTelemetry trace export from Claude Managed Agents, the Messages API and the Claude SDKs, with traces following the OpenTelemetry GenAI semantic conventions.[4] In practice that is two separate pipelines that you can run alone or together.[2]
| SDK spans | API spans | |
|---|---|---|
| Emitted by | The anthropic package inside your process | The Claude API, inside Anthropic |
| Configured | In code or with ANTHROPIC_OPEN_TELEMETRY_* variables, plus your own OTel exporter | As a destination in the Claude Console, Admin API or CLI |
| Who can turn it on | Anyone who can change the application | Organization admin |
| Covers | Each request your client sends, tools run by the tool runner, other calls such as file uploads | Each model run, server tools such as web search, compaction, Managed Agents turns |
| Span kind | CLIENT for requests, INTERNAL for tools | SERVER for requests, INTERNAL for steps |
| Content control | traces.content_mode on the client | Content mode on the destination |
| Coverage | Clients that use the SDK | Any client, SDK or not |
The SDK sends a W3C traceparent header and the API parents its spans under it, so both halves land in one trace when they go to the same backend.[3] If your sampler drops a trace, the sampled flag in that header is off and the API emits nothing for the request. A request that arrives with no traceparent still gets API spans, in a new trace.[3]
Which half do you want? If you only need to know why a Managed Agents session went sideways or what a model run cost in tokens, the destination alone is enough, and it covers every client including ones you do not control. If you want the span for your own tool code, or the request wrapped inside your web handler's span, add the SDK half. Teams already tracking agent behavior at the application layer can pair this with the AI Agent Observability and Failure-Mode Instrumentation Pack for the alerting side.
Decide the content mode before you click Add destination
Every destination and every SDK client has a content mode.[2]
- Metadata only (
metadata_onlyin the SDK) is the default. Spans carry identifiers, timing, status, token counts, and text you choose to expose, such as agent and tool names and MCP server names. - Full content (
contentin the SDK) adds model prompts and responses, including the system prompt, the input messages and the output messages. - Attributes that hold prompts and responses are tagged Content in the span reference.[8]
Full content is what makes traces useful for debugging and for building evals from real traffic. It is also a copy of your users' conversations, sitting in a third-party system. The docs say plainly that the platform stores it under its own access and retention settings and that you should check those meet your requirements.[2] The cookbook's production checklist is blunter: keep metadata_only until your data policy allows otherwise.[3]
Three details that change the decision:
- Even in Metadata only, the SDK still exports tool names and descriptions, agent names, MCP server names and the
conversation_idyou set, so do not put user data in that ID.[3] - If your organization has a HIPAA, FERPA or K-12 data-handling restriction with Anthropic, destinations export only metadata whatever the setting says. SDK spans are not affected by that rule.[2]
- With zero data retention, Full content is still allowed for Messages API requests, and the API holds the exported content in memory only until delivery. Claude Managed Agents is not ZDR eligible, and its retention is unchanged by OpenTelemetry.[2]
The fourth thing is size. With Full content each span holds up to 0.75 MB of content by default. Over the limit, request spans drop the system prompt and the earliest messages first and set anthropic.content.truncated to true.[2] If your backend rejects large payloads, lower the cap.
Set up a Console destination
You need the admin role in the Console organization, an OTLP/HTTP endpoint that accepts protobuf at an HTTPS URL on port 443, and credentials for it. If you run your own OpenTelemetry Collector, its OTLP/HTTP receiver listens on port 4318 by default, so put HTTPS on 443 in front of it or reconfigure the receiver.[1]
Open the organization's OpenTelemetry settings page in the Console, click Add destination, and fill in the fields below.[1]
| Field | What to enter |
|---|---|
| Provider | A listed platform, or Custom. A listed platform replaces the endpoint and headers fields with its own details, such as an API key. |
| Name | Optional label. |
| OTLP endpoint URL | Base HTTPS URL with a hostname, not an IP. A path prefix is allowed. Do not add /v1/traces, because the API adds it. |
| Request headers | Your platform's auth header. The Console does not show the values again after you save. |
| Content mode | Metadata only or Full content. |
| Workspaces | All, Selected, or All except. |
| OTLP traces endpoint URL | Optional, under Advanced settings. Use it when your platform receives traces somewhere other than the base URL plus /v1/traces. Same host as the base URL. |
| Maximum content size in MB | Optional, Full content only. Empty means as much as the API allows. |
Save it, open the destination's More actions menu and click Test. A test span named anthropic.test should reach your platform.[1] Then send a real request from the playground or your app. The Delivery column should read Healthy within about a minute, and in your backend you filter on service.name equal to claude-platform to find the API spans.[1]
Prefer code over clicking? The same settings exist in the Admin API behind the telemetry-destinations-2026-08-11 beta header, with a matching CLI command and SDK methods. The create call takes endpoint_url, headers, traces.content_mode and workspaces.type.[1]
Choosing workspaces
A destination only receives spans from workspaces it covers, and the API sends to every enabled destination that covers the workspace where the request or session runs. All includes the Default Workspace and workspaces created later. That is a useful privacy lever: send the production workspace with Metadata only to your main backend and a staging workspace with Full content to a separate project.[1]
One backend end to end: Honeycomb
Honeycomb has a Claude Platform page, and it is the cleanest example because the Console has a built-in Honeycomb provider.[6]
- In the Console, open the OpenTelemetry settings and clear any workspace filter so it shows All.
- Click Add destination and pick Honeycomb as the Provider. Optionally name it, for example Honeycomb production.
- Keep the default US region, which uses
https://api.honeycomb.io. - Paste a Honeycomb Ingest API key. Honeycomb notes that the key needs permission to create datasets.
- Leave Dataset empty. Honeycomb names it
claude-platform. - Choose the content mode and the workspaces, then click Add destination.
EU teams cannot pick EU in the region picker. Honeycomb documents two workarounds: edit the destination and set the OTLP endpoint URL to https://api.eu1.honeycomb.io, or choose Custom with that URL and a request header named x-honeycomb-team holding the ingest key.[6]
To find a trace, open the environment that matches your key, go to Query, choose the claude-platform dataset and run the query, then click a point and View trace. Managed Agents conversations show up in Honeycomb's Agent Timeline, while Messages API requests carry no conversation ID, so you find those as plain traces.[6]
Grafana Cloud has a dedicated guide for Claude Platform traces, linked from Anthropic's overview.[2] Its general OTLP page shows the endpoint pattern https://otlp-gateway-<REGION>.grafana.net/otlp and says to take the exact OTLP endpoint and a generated token from your stack's OpenTelemetry tile.[7] Anthropic's overview lists Datadog, Langfuse, LangSmith, New Relic, PostHog, Sentry, Splunk, Arize AI, Braintrust and Databricks as partner platforms too, each with its own setup page. Follow each vendor's own page for its exact endpoint and headers.[2]
What a trace looks like
Span names follow one rule. They start with anthropic. followed by the API method with dots and without beta, so client.messages.create() becomes anthropic.messages.create and client.beta.sessions.events.send() becomes anthropic.sessions.events.send.[3] Under a Messages API request, the API adds spans for each model request and for each server tool or MCP connector tool it runs.[2]
| Span | Emitted by | What it marks |
|---|---|---|
anthropic.messages.create | SDK (CLIENT) and API (SERVER) | One Messages API request |
anthropic.model_request | API | One model run inside a request or turn |
anthropic.messages.tool_runner | SDK | The whole tool-runner loop |
anthropic.custom_tool_use <name> | SDK | A tool you run yourself |
anthropic.tool_use <name> | API | A server tool such as web search, or a prebuilt toolset tool such as bash |
anthropic.mcp_tool_use <name> | API and SDK | An MCP tool; the API span carries anthropic.mcp.server.name |
anthropic.session.turn | API | One agent turn in a Managed Agents session |
anthropic.session.outcome_evaluation | API | An outcome evaluation in a session |
anthropic.compaction | API | Context compaction |
Attribute names come from the GenAI conventions plus an anthropic. namespace. The ones you will actually query on:[3]
gen_ai.operation.namewith valueschat,invoke_agentandexecute_toolgen_ai.request.modelandgen_ai.response.modelgen_ai.usage.input_tokensandgen_ai.usage.output_tokensanthropic.message.stop_reason, which the cookbook says to alert on when it equalsmax_tokensanthropic.request.id, which matches therequest-idheader and joins SDK spans to API spansanthropic.session.idandgen_ai.conversation.idfor grouping a whole session or one thread of it
One gotcha will bite anyone building cost dashboards. gen_ai.usage.input_tokens already includes cache-read and cache-creation tokens, so adding the cache attributes on top double counts.[3] Token usage also repeats across several spans of one request. For a Messages API request, sum either the API anthropic.messages.create spans or their anthropic.model_request children, never both, plus anthropic.compaction if present. For a Managed Agents session, sum anthropic.model_request and anthropic.session.outcome_evaluation.[2] If you want a dollar figure before you build any of that, the agent run cost simulator gives a quick estimate from run length and token assumptions.
To read a Managed Agents session as a transcript, group spans by gen_ai.conversation.id for one thread, or by anthropic.session.id across traces for the whole session, since a session's spans can sit in several traces.[2] For background on the sandbox those sessions run in, see our Managed Agents self-hosted sandbox guide.
Adding the SDK half
The Python cookbook registers a tracer provider before the first traced call and then builds the client with no tracing arguments. The OTLP exporter reads the standard OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS variables.[3] To switch the client to Full content, pass open_telemetry={"traces": {"content_mode": "content"}} or set ANTHROPIC_OPEN_TELEMETRY_TRACES_CONTENT_MODE=content. Defaults are propagation on, metadata_only, and a 750,000-byte content cap.[3]
Version check: the cookbook installs anthropic>=1.14.0 (its sample output still prints 1.13.0).[3] PyPI shows 1.14.0 published on 14 October 2026, the launch day, and 1.16.0 as the latest on 20 October, so run pip show anthropic and upgrade if you are below 1.14.0.
Claude Code and the Agent SDK are a different setup
Do not mix these up. Claude Code and the Agent SDK export their own telemetry from the CLI process, enabled with CLAUDE_CODE_ENABLE_TELEMETRY=1 and a per-signal exporter variable, with traces additionally needing CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1.[5] Their spans are named claude_code.interaction, claude_code.llm_request and claude_code.tool, and the service name defaults to claude-code.[5] The Agent SDK docs add one hard rule: never set the console exporter, because the SDK uses standard output as its message channel.[5] Content there is opt-in through separate variables such as OTEL_LOG_USER_PROMPTS.[5] If you track what Claude Code itself changes between releases, our Claude Code 2.1.293 to 2.1.302 changelog is the place to start.
Limits, delivery and beta caveats
| Item | What the docs say |
|---|---|
| Destinations per organization | 10, including disabled ones |
| Selected workspaces per destination | 1,000 |
| Request headers per destination | 20; name up to 128 bytes, value up to 4,096 bytes, all together 16,384 bytes |
| Endpoint URL length | 2,048 characters |
| Delivery guarantee | At least once, best effort. Spans can arrive twice or be lost. |
| Compression | First request is gzip. On a 400 or 415 the API resends without compression. |
| Retries | A limited number of later retries after timeouts, connection, TLS or DNS failures, and 408, 429 or 5xx responses |
| Timeouts | 5 seconds for the TLS handshake, 5 seconds for response headers, 10 seconds per delivery in total |
| Auto-disable | On any 3xx redirect, on a hostname that resolves to a non-public IP, or after 24 hours of failed deliveries |
All of that comes from the API setup page.[1] Two practical consequences. First, deduplicate on trace ID plus span ID if your backend does not do it for you. Second, a redirecting endpoint is fatal, so use the final URL, not the one your vendor forwards from.
On sampling, the docs say nothing about Anthropic-side sampling rates. What they do say is that the sampled flag in your traceparent controls whether the API emits spans for a request at all.[1] On cost, neither the launch article nor the docs state a price for the export, so treat that as unconfirmed and watch your backend's ingest bill instead.[4]
The beta wording is direct: span names and attributes can change during the beta, and the feature is provided under your agreement with Anthropic including the Beta Services section of the Service Specific Terms.[8] Pin your dashboards to a small set of attributes and expect to touch them again. And do not bill from spans. The overview says exported spans are not a complete record of API usage; use the Usage API for that.[2]
Frequently asked questions
Do I need to change my application code to get API spans?
No. The destination is configured in the Console and covers every client in the organization, SDK or not. Code changes are only needed if you also want SDK spans or want API spans nested under your own spans.[1]
Who can add a destination?
The admin role in the Console organization. With the developer role you can view destinations. A developer who is also a Workspace Admin can add or remove their own workspace on a Selected destination.[1]
Does setting the SDK to metadata_only stop prompts reaching my backend?
Not for API spans. The destination content mode is independent, and the SDK content setting has no effect on API spans. Set both deliberately.[3]
Can I use these spans to calculate my bill?
No. Delivery is best effort, callers can switch off sampling per request, and Anthropic points to the Usage API for accounting.[2]
Sources
- Set up OpenTelemetry with the Claude API (Claude docs)
- OpenTelemetry for the Claude API (Claude docs)
- Tracing Claude API and Managed Agents with OpenTelemetry (Claude cookbook)
- Agent observability on the Claude Platform (Anthropic, 14 October 2026)
- Observability with OpenTelemetry (Agent SDK docs)
- Send Claude Platform traces to Honeycomb (Honeycomb docs)
- Send OTLP data to Grafana Cloud (Grafana docs)
- OpenTelemetry span reference (Claude docs)
Written by
WOWHOW
The WOWHOW team brings 14+ years of production engineering experience. Every tool and product in the catalog is built, tested, and curated in-house.
Monday memo · free
One insight, every Monday. 7am IST.
1 field report, 3 links, 1 tool we actually use. No fluff, no spam.
Beyond the writing
Need production-ready templates?
Free browser tools with no signup, plus premium dev templates and starter kits.
Comments · 0
Beta: comments are stored locally on your device and not visible to other readers.
No comments yet. Be the first to share your thoughts.