Claude Code OpenTelemetry: Track Cost per Developer and Repo
Claude Code can export its own usage over OpenTelemetry, including an estimated dollar cost for every model request. Turn on telemetry, enable the logs exporter, set a protocol, and point it at a receiver. Then each developer’s spend arrives as claude_code.api_request events carrying cost_usd, the model, and token counts. Add OTEL_METRICS_INCLUDE_REPOSITORY=true and each event also names the repository. That’s enough to total Claude Code spend per developer and per repo with nothing extra installed.
This guide covers the settings, the fields that matter for cost, the gotchas, and where to send the data.
The settings
In ~/.claude/settings.json (or as environment variables):
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://your-collector.example.com",
"OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer your-token",
"OTEL_METRICS_INCLUDE_REPOSITORY": "true"
}
}
| Setting | What it does |
|---|---|
CLAUDE_CODE_ENABLE_TELEMETRY | Turns telemetry on. Off by default. |
OTEL_LOGS_EXPORTER | Exports events, including one api_request per model call. |
OTEL_EXPORTER_OTLP_PROTOCOL | grpc, http/json, or http/protobuf. There is no default. |
OTEL_EXPORTER_OTLP_ENDPOINT | Base URL. HTTP exporters append /v1/logs and /v1/metrics. |
OTEL_EXPORTER_OTLP_HEADERS | Auth for the receiver. Use one token per developer if the receiver attributes by token. |
OTEL_METRICS_INCLUDE_REPOSITORY | Adds the repository from the origin remote. Off by default; Claude Code 2.1.269 or later. |
To roll this out to a whole team, put the shared settings in a managed settings file instead of asking each developer to edit theirs. If your receiver attributes spend by token, keep the header out of the managed file, since one shared token would merge everyone into one person; each developer sets their own. See Anthropic’s monitoring docs.
The fields that matter for cost
Each claude_code.api_request event carries:
cost_usd: estimated cost of the request in USD, andcost_usd_microsas an integermodelinput_tokens,output_tokens,cache_read_tokens,cache_creation_tokens(input excludes cached tokens)session.idandprompt.iduser.emailwhen the developer is signed in to a Claude account, anduser.id, a random per-install idvcs.owner.nameandvcs.repository.name, when the repository setting is on
Summing cost_usd grouped by user.email (or by token) gives cost per developer. Don’t group by user.id: it’s an anonymous id that changes if ~/.claude.json is deleted. Grouping by vcs.repository.name gives cost per repo. Grouping by session.id gives cost per session.
The claude_code.cost.usage metric carries the same spend as a counter on a 60-second interval. It’s fine for a running total on a chart. The per-request event is better for attribution because it ties each dollar to a session, a prompt, and a repository.
Gotchas
- No default protocol. Without
OTEL_EXPORTER_OTLP_PROTOCOL, the exporter doesn’t send. Check your receiver supports the one you pick: many hosted HTTP endpoints don’t serve grpc. - Restart required. Settings are read at startup.
- Noise. One prompt can produce dozens of events: hooks registered, MCP connections, tool results. If you store everything, keep
api_request,api_error, anduser_prompt, and drop the rest. - Repo attributes are off by default, and they’re omitted when the session has no
originremote. - No branch or pull request. Telemetry names the repo but not the branch, so cost per PR needs another source.
- Estimates.
cost_usdis an estimate at list prices. It won’t match an invoice that has seat plans or discounts. - Claude Code only. Cursor’s OpenTelemetry export is limited to Enterprise. Codex and Gemini CLI need their own setup, so a mixed-tool team won’t get one view from this alone.
Where to send it
- Your own stack. An OpenTelemetry Collector into Grafana, Honeycomb, Datadog, or any OTLP backend. You build the queries and dashboards yourself.
- PromptConduit. Point the endpoint at
https://api.promptconduit.dev/v1/otlpwith your API key, and Claude Code spend counts on the team page. It’s broken down by member, model, repository, client, and day, with budgets, email and Slack alerts, and a savings report. Setup is in the Claude Code telemetry docs. It acceptshttp/protobufandhttp/json, gzip or not.
For branch and pull request attribution, and for Cursor, Codex, and Gemini CLI in the same report, add the CLI. Where both send the same session, the CLI’s figures are used and the telemetry cost is left out, so nothing is counted twice. See how to attribute AI coding spend to teams and repos.
Frequently asked questions
Does Claude Code support OpenTelemetry?
Yes. Set CLAUDE_CODE_ENABLE_TELEMETRY=1 and choose exporters for metrics, logs, or both. Claude Code sends OTLP over grpc, http/json, or http/protobuf to the endpoint you configure.
Which Claude Code telemetry carries cost?
Two signals. The claude_code.cost.usage metric is a running total, exported every 60 seconds by default. The claude_code.api_request log event arrives once per model request, every 5 seconds by default, with cost_usd, the model, and token counts. For attribution, use the event: it carries the session and prompt ids, and the repository when that setting is on.
How do I get the repository in Claude Code telemetry?
Set OTEL_METRICS_INCLUDE_REPOSITORY=true (Claude Code 2.1.269 or later). Metrics and events then carry vcs.owner.name and vcs.repository.name from the session's origin remote. It is off by default.
Why is nothing arriving?
Usually the protocol. Claude Code has no default OTLP protocol, so set OTEL_EXPORTER_OTLP_PROTOCOL. Then check the receiver speaks that protocol: many hosted HTTP endpoints don't accept grpc. Restart Claude Code after changing settings.
Is cost_usd exact?
No. Claude Code's docs describe it as an estimated cost. It's good for trends and approximate chargeback, not for reconciling an invoice.