Skip to content

Send Claude Platform traces to Logfire

See what Claude did for each request your app sends: every Claude Managed Agents turn, each model call, each tool the agent ran, and the tokens it used.

There are two parts:

  1. Add Logfire in the Claude Console. Anthropic then sends Claude’s spans to Logfire for every request, from any language, with no code changes. A span is one unit of work, such as a model call, with a name, a start, and a duration.
  2. Optional: link them to your app. Add logfire.configure() to your Python app, and Claude’s spans appear inside your own traces (the full journey of one request, made of nested spans).

What you’ll see

SpanWhat it shows
anthropic.session.turnOne Managed Agents turn: the conversation, including the system prompt and tool calls.
anthropic.tool_use <tool>A tool the agent ran, such as bash or web search, with its input and output.
anthropic.messages.createOne Messages API request: the prompt and the response.
anthropic.model_requestOne model call: the model, token usage, and timing. It has no prompt or response.

Claude’s spans have the service name claude-platform. Spans from your own app have your app’s service name.

Before you start

You need:

  • A Logfire project and a write token (the credential that lets a service send data to a project), from Settings → Write tokens in your project.
  • The admin role in your organization in the Claude Console. This is the organization that owns your API keys, which is separate from any claude.ai organization.

Step 1: Add Logfire in the Claude Console

  1. Open the Console’s OpenTelemetry settings and click Add destination.
  2. Leave Provider as Custom, and set Name to Logfire.
  3. Set OTLP endpoint URL to the address of your Logfire data region. Don’t add a path: the Console adds it.
https://logfire-us.pydantic.dev
  1. Under Request headers, add a header named Authorization with your write token as the value. Paste the token on its own, without Bearer in front.
  2. Choose a Content mode: Full content to read conversations in Logfire, or Metadata only to leave them out.
  3. Under Workspaces, choose which Claude workspaces send spans: All, Selected, or All except.
  4. Click Add destination.

The Add destination form in the Claude Console, filled in for Logfire

Check it: open the destination’s ⋮ menu and click Test. An anthropic.test span appears in Logfire’s Live view within about a minute. After your next real request, the Delivery column shows Healthy.

The Logfire destination in the Claude Console with Delivery showing Healthy

That’s all you need to see Claude’s spans in Logfire. Each request shows up as its own trace.

This step puts Claude’s spans inside the trace of the code that made the call, so you can see which user request or job asked Claude for what.

Install logfire and the Claude SDK (version 1.14.0 or later):

Terminal
pip install logfire anthropic

Call logfire.configure() before you create the client. You don’t need any other setup: the SDK sends its spans through Logfire, and tells Claude which of your spans made each call.

from anthropic import Anthropic

import logfire

logfire.configure()

client = Anthropic(open_telemetry={'traces': {'content_mode': 'content'}})

with logfire.span('fibonacci agent'):
    environment = client.beta.environments.create(
        name='fibonacci-env',
        config={'type': 'cloud', 'networking': {'type': 'limited', 'allow_package_managers': True}},
    )
    agent = client.beta.agents.create(
        name='Fibonacci agent',
        model='claude-sonnet-5-5',
        system='You are a helpful coding assistant. Keep replies short.',
        tools=[{'type': 'agent_toolset_20260401'}],
    )
    session = client.beta.sessions.create(agent=agent.id, environment_id=environment.id)

    with client.beta.sessions.events.stream(session.id) as stream:
        client.beta.sessions.events.send(
            session.id,
            events=[
                {
                    'type': 'user.message',
                    'content': [
                        {'type': 'text', 'text': 'Print the first 10 Fibonacci numbers with a one-line Python command.'}
                    ],
                }
            ],
        )
        for event in stream:
            if event.type == 'agent.message':
                print(''.join(block.text for block in event.content if block.type == 'text'))
            elif event.type == 'session.status_idle':
                break

The agent runs the command in its sandbox and replies with something like:

Output: `0 1 1 2 3 5 8 13 21 34`

open_telemetry={'traces': {'content_mode': 'content'}} adds prompts and responses to your app’s spans too. Leave it out to keep them to metadata only, unless the environment variable ANTHROPIC_OPEN_TELEMETRY_TRACES_CONTENT_MODE is set to content.

Good to know:

  • Web apps: if you already instrument your web framework, Claude’s spans appear under each incoming request, for example GET /chat, with no extra code.
  • Sampling: if you sample traces in logfire.configure(), Claude follows your choice. A trace you don’t keep has no Claude spans.

Group calls into a conversation

Give related calls the same conversation_id. The SDK records it as gen_ai.conversation.id on your app’s spans. It is sent in both content modes, so don’t put personal data in it.

from anthropic import Anthropic

import logfire

logfire.configure()

client = Anthropic()
conversation = client.with_options(open_telemetry={**client.open_telemetry, 'conversation_id': 'conv_42'})

conversation.messages.create(
    model='claude-haiku-5-5',
    max_tokens=100,
    messages=[{'role': 'user', 'content': 'Hello, Claude'}],
)

Without the Claude SDK

Claude reads your trace context from the traceparent request header. If you call the API with httpx, logfire.instrument_httpx() adds that header for you. Install the httpx extra first:

Terminal
pip install 'logfire[httpx]'

Then:

import os

import httpx

import logfire

logfire.configure()
logfire.instrument_httpx()

with logfire.span('summarize'):
    response = httpx.post(
        'https://api.anthropic.com/v1/messages',
        headers={
            'x-api-key': os.environ['ANTHROPIC_API_KEY'],
            'anthropic-version': '2023-06-01',
        },
        json={
            'model': 'claude-haiku-5-5',
            'max_tokens': 100,
            'messages': [{'role': 'user', 'content': 'Hello, Claude'}],
        },
        timeout=60,
    )
    print(response.json()['content'][0]['text'])

With another HTTP client, add the header yourself with opentelemetry.propagate.inject(headers) before you send the request.

See it in Logfire

Run an example, then open the Live view. Within about a minute you should see your trace. Expand it to see your app’s spans with Claude’s spans under them. Click a span to read the conversation, with the model, tokens, and cost.

A Managed Agents session, with the turn open:

Logfire Live view of a Managed Agents session with the turn span open

A Messages API request, with the second call open after the tool ran:

Logfire Live view of a Messages API request with the tool runner, with a request span open

Find what you need with SQL

Use the Explore view to query Claude’s spans.

All spans of one session. A session can be spread over several traces, for example when you send a later message from a new request:

SELECT start_timestamp, span_name, duration
FROM records
WHERE attributes->>'anthropic.session.id' = 'sesn_...'
ORDER BY start_timestamp

One request. Each response has a request-id header. Find its spans with:

SELECT trace_id, span_name, service_name
FROM records
WHERE attributes->>'anthropic.request.id' = 'req_...'

Token usage. The same tokens are recorded on more than one span of a request: on your app’s span, on Claude’s request span, and on the model call. To count each token once in SQL, add up only the model calls, context compactions, and (for Managed Agents) outcome evaluations:

SELECT
  trace_id,
  sum((attributes->>'gen_ai.usage.input_tokens')::int) AS input_tokens,
  sum((attributes->>'gen_ai.usage.output_tokens')::int) AS output_tokens
FROM records
WHERE span_name IN ('anthropic.model_request', 'anthropic.compaction', 'anthropic.session.outcome_evaluation')
GROUP BY trace_id

Troubleshooting

ProblemFix
No Add destination buttonClear the Workspace filter at the top of the page with its ×. The button only shows when no workspace is selected. Also check that you have the admin role.
Delivery shows Failing (401 or 403)The write token is wrong. Paste a valid token for this project, without Bearer.
Delivery shows Failing (404)The endpoint has a path. Use only https://logfire-us.pydantic.dev or https://logfire-eu.pydantic.dev.
Delivery shows DisabledAnthropic turns a destination off after 24 hours of failed deliveries. Fix the cause, then click Enable in its ⋮ menu. Spans from while it was off aren’t sent later.
Test works but your requests don’t show upThe destination doesn’t include the workspace of your API key. Check its Workspaces.
Claude’s spans aren’t inside your app’s tracesCall logfire.configure() before creating the client, and make calls inside a span.
No prompts or responsesThe destination is set to Metadata only. If your organization has a HIPAA, FERPA, or K-12 data-handling restriction with Anthropic, Claude’s spans only contain metadata, whatever the content mode.
Calls through Amazon Bedrock or Google Vertex AI don’t show upThe Console export only covers the Claude Platform, including Claude Platform on AWS. For Amazon Bedrock, use the Anthropic integration.

Next steps