What Claude Code OpenTelemetry gives you
Claude Code OpenTelemetry export sends usage data from every session to a collector you run. Metrics arrive as time series: sessions, lines changed, commits, pull requests, tokens, estimated cost and active time. Events arrive through the logs protocol: each prompt, API request, API error, tool result and permission decision. Traces are available as a beta. Nothing is exported until someone turns it on.
Team and Enterprise plans already get an analytics dashboard with active users, sessions, accept rates and contribution metrics. That covers adoption. OpenTelemetry is what you add when you need per-user token counts and cost estimates in your own monitoring stack, alerts on spend spikes, or a breakdown by team, cost center, skill or model that the dashboard does not give you. My take: if you are paying for Claude Code across more than a handful of people, you want this on before the first surprise bill, not after.
Quick setup on one machine
Test on your own machine before you roll anything out. You need a collector that accepts OTLP, running locally or somewhere your laptop can reach. Then set these variables in your shell or in the env block of ~/.claude/settings.json:
- CLAUDE_CODE_ENABLE_TELEMETRY=1. Nothing is exported without it.
- OTEL_METRICS_EXPORTER=otlp and OTEL_LOGS_EXPORTER=otlp. Metrics also accept prometheus or console, and either can be none.
- OTEL_EXPORTER_OTLP_PROTOCOL set to grpc, http/json or http/protobuf. Claude Code has no default protocol, so leaving this out is the most common reason nothing arrives.
- OTEL_EXPORTER_OTLP_ENDPOINT set to your collector, such as http://localhost:4317 for gRPC.
- OTEL_EXPORTER_OTLP_HEADERS if your collector needs a token, in the form Authorization=Bearer your-token.
Metrics export every 60 seconds by default and logs every 5 seconds. While testing, drop OTEL_METRIC_EXPORT_INTERVAL to 10000 so you are not waiting a minute for each check, then set it back for production. Start a session in the desktop app or the terminal and look for claude_code.session.count in your backend. For a logs-only setup, send a prompt and look for the claude_code.user_prompt event.
Roll it out to a team with managed settings
For a company, do not ask every developer to edit their shell. Put the same variables in the env block of your managed settings file and push it with your device management. The desktop app's Code tab reads managed settings too, so desktop users are covered alongside terminal users. The settings.json guide covers where each settings file lives and which one wins.
Managed settings also lock the destination. When you set OTEL_EXPORTER_OTLP_ENDPOINT there, Claude Code removes any per-signal endpoint a developer set, so nobody can quietly send one signal to a different collector. Setting headers or client certificates there removes developer-set endpoints too, because your credentials should only ever reach the collector you chose. The exporter selectors are the exception: a developer can still switch a signal to none or console unless you set OTEL_METRICS_EXPORTER and OTEL_LOGS_EXPORTER in managed settings as well. Set all of them.
Repositories cannot interfere in the other direction. Claude Code ignores the OpenTelemetry exporter variables in a repo's .claude/settings.json and .claude/settings.local.json, so a cloned project cannot switch telemetry on, choose where it goes or capture content. A repo can only turn a signal off by setting its exporter to none, and only when managed settings have not already set that variable.
The metrics that matter
Claude Code OpenTelemetry metrics and what to use them for
| Metric | What it counts | Use it for |
|---|---|---|
| claude_code.session.count | Sessions started, with a start_type of fresh, resume or continue | Adoption over time |
| claude_code.cost.usage | Estimated cost in USD after each API request | Spend by person, team, model, skill or subagent |
| claude_code.token.usage | Tokens by type: input, output, cacheRead, cacheCreation | Spotting heavy sessions and cache behavior |
| claude_code.lines_of_code.count | Lines added and removed, by model | Rough output volume |
| claude_code.commit.count | Commits created through Claude Code | Workflow impact |
| claude_code.pull_request.count | Pull and merge requests created | Workflow impact |
| claude_code.code_edit_tool.decision | Accept or reject decisions on Edit, Write and NotebookEdit | Trust and review habits by language |
| claude_code.active_time.total | Active seconds, split into user and cli time | Real usage, not idle sessions left open |
The cost metric is an estimate. For billing, your API provider's own records are the source of truth. Use claude_code.cost.usage for trends and alerts, not for invoices. The useful part is the breakdown: cost and token metrics carry model, effort level and query_source, which tells you whether spend came from the main conversation, subagents or background requests.
The three alerts I would set first are a cost spike per user per day, unusual token volume, and a jump in session count from one account. All three come straight from these metrics. If you are trying to bring spend down after you see it, how to cut Claude Code token usage and the effort levels guide are the two levers that move it most.
Split usage by team and cost center
Every metric and event already carries a session ID, your organization ID, account identifiers and, when signed in, the user's email. To add your own grouping, set OTEL_RESOURCE_ATTRIBUTES with comma-separated key=value pairs, for example department=engineering,team.id=platform,cost_center=eng-123. Those keys become labels on every metric and event, so you can build a dashboard per team or charge spend back to a cost center.
- No spaces in values. Use underscores, camelCase or percent-encoding. Wrapping a value in quotes keeps the quotes in the value, it does not escape the space.
- Every custom key is a new label on every series, so high-cardinality values raise your storage cost. If you only need them on the resource block, set OTEL_METRICS_INCLUDE_RESOURCE_ATTRIBUTES=false.
- Session IDs and account IDs are on by default. Version, entrypoint and repository attributes are off by default and each has its own OTEL_METRICS_INCLUDE flag.
- Desktop app sessions report service.name as claude-code-desktop, not claude-code. If your dashboards filter on claude-code, add the desktop value or you will miss everyone using the app.
What stays private by default
This is the question every security team asks first, and the defaults are sensible. Raw file contents and code snippets are never in metrics or events. Prompt text is not collected, only prompt length. Response text is not collected, only its length. Tool arguments like Bash commands and file paths are not logged. All of it goes only to the endpoint you configure.
Content flags and what each one adds
| Flag | What it adds | Default |
|---|---|---|
| OTEL_LOG_USER_PROMPTS=1 | Prompt text on user_prompt events | Off |
| OTEL_LOG_ASSISTANT_RESPONSES=1 | Response text on assistant_response events. Falls back to the prompts flag when unset | Off |
| OTEL_LOG_TOOL_DETAILS=1 | Bash commands, file paths, URLs, and real skill, plugin and MCP names | Off |
| OTEL_LOG_TOOL_CONTENT=1 | Tool output in trace spans, such as file contents and command output | Off, needs tracing |
| OTEL_LOG_RAW_API_BODIES | Full API request and response bodies, including the whole conversation | Off |
My advice: leave the content flags off for the first rollout. Usage and cost answer most of what a team lead wants to know, and turning on prompt or tool content changes the conversation with your developers and your legal team. If you need it later for audits, turn it on deliberately and filter it in your collector. If you set OTEL_LOG_ASSISTANT_RESPONSES=0 explicitly, you can collect prompts without collecting responses.
Short, practical drops on skills, MCP, agents, prompts, and more. No spam, unsubscribe anytime.
Frequently asked questions
How do I enable OpenTelemetry in Claude Code?
Set CLAUDE_CODE_ENABLE_TELEMETRY=1, set OTEL_METRICS_EXPORTER and OTEL_LOGS_EXPORTER to otlp, set OTEL_EXPORTER_OTLP_PROTOCOL and OTEL_EXPORTER_OTLP_ENDPOINT for your collector, and add OTEL_EXPORTER_OTLP_HEADERS if it needs a token. Then check your backend for the claude_code.session.count metric.
Does Claude Code OpenTelemetry send my prompts or code?
Not by default. Metrics and events never include raw file contents or code snippets, and prompt and response text are recorded only as lengths unless you set OTEL_LOG_USER_PROMPTS or OTEL_LOG_ASSISTANT_RESPONSES. Everything goes only to the endpoint you configure.
How do I turn on Claude Code telemetry for my whole team?
Put the variables in the env block of your managed settings file and deploy it to every machine. An endpoint or credential set in managed settings removes conflicting developer-set endpoints. Set the exporter selectors there too so developers cannot switch a signal off.
Is the Claude Code cost metric accurate enough for billing?
No. claude_code.cost.usage is an estimate meant for trends, alerts and attribution. Use your API provider's billing records for actual charges.
Why is no Claude Code telemetry arriving at my collector?
The usual causes are a missing OTEL_EXPORTER_OTLP_PROTOCOL, since Claude Code has no default, a wrong endpoint, or a collector your machine cannot reach. Start Claude Code with claude --debug-file and a path, then look for [3P telemetry] errors in that file.
Last reviewed by David Iya on November 1, 2026

