Claude Code cost per developer: the 8 metrics to instrument before you quote a figure

Claude Code exports eight OpenTelemetry metrics, including claude_code.cost.usage in USD and claude_code.token.usage in tokens. Attributing Claude Code spend per developer needs three things: telemetry enabled through managed settings, a team label in OTEL_RESOURCE_ATTRIBUTES, and reconciliation against the Admin Cost API. Pexon runs the full measurement design before quoting a per-developer figure.

This page has no euro figure, and that is deliberate

We are not going to tell you what Claude Code costs per developer per month, because we do not yet have ninety days of our own data and neither does anyone else who is willing to show their working. What follows is the measurement design instead: what to instrument, what each source of data can and cannot tell you, and which of the resulting numbers will embarrass you in a budget review.

That is not modesty. Cost per developer is a product of four things that vary enormously between organisations: which model answers each step, how much of the prompt prefix is cacheable, how many turns a task takes before it lands, and whether engineers run one agent or four in parallel. Any two of those can move the monthly figure by a factor that makes a borrowed benchmark worse than no benchmark, because a borrowed benchmark gets quoted with confidence.

What does transfer is the instrumentation. Anthropic documents eight OpenTelemetry metrics for Claude Code, three Admin API report endpoints, and a set of defaults that decide whether your numbers are attributable at all. Those are stable enough to build on, and they are the subject of this piece.

The figure that comes out at the end will be yours. It will not match ours when we eventually publish one, and it should not.

Where Claude Code cost data actually comes from

There are five sources, they have different granularities, different freshness and — the part that catches people — different blind spots. Reading one of them and calling it the cost of Claude Code is the first mistake.

The two OpenTelemetry paths are yours: Claude Code exports to a collector you run, so the data never leaves your estate and you can aggregate or discard attributes before storage. The three Admin API paths are Anthropic's: authoritative for billing reconciliation, coarser in time, and gated behind an Admin API key that a standard API key cannot substitute for.

One structural point before the table. The Admin API is unavailable for individual accounts, and on Claude Platform on AWS the programmatic usage, cost and Claude Code Analytics endpoints are not available at all — Anthropic's instruction there is to read the Usage and Cost pages in the Claude Console instead. If either applies to you, the OpenTelemetry path is not the convenient option, it is the only programmatic one.

The five sources

Granularity, freshness and the blind spot

SourceGranularityFreshnessBlind spot
OTel metrics (claude_code.cost.usage)Per session, with model, user and custom labelsOTEL_METRIC_EXPORT_INTERVAL, default 60000 msCost is an estimate; you must run and secure a collector
OTel events (claude_code.api_request)One record per API request, with cache_read and cache_creation tokensOTEL_LOGS_EXPORT_INTERVAL, default 5000 msHigh volume; prompt text is redacted unless OTEL_LOG_USER_PROMPTS=1
Claude Code Analytics APIOne record per user per UTC day, with model breakdownUp to one hour; records younger than an hour are excludedClaude API only — Bedrock, Foundry, Vertex and Claude Platform on AWS are not included
Usage API (usage_report/messages)1m, 1h or 1d buckets, grouped by model, workspace or service tierTypically within five minutesTokens, not Claude Code specifically; Workbench usage has a null api_key_id
Cost API (cost_report)Daily buckets only, grouped by workspace or descriptionTypically within five minutesPriority Tier costs are excluded from this endpoint entirely

The instrumentation checklist, in the order it has to be done

Enable telemetry centrally before anyone opts in individually, because a metric that exists on four laptops and not on the other forty produces a number that is worse than none. Managed settings are the mechanism: environment variables defined there have high precedence and cannot be overridden by a developer, and the file can be distributed through MDM alongside everything else you already push to engineering machines.

The checklist below is the artefact. It is ordered by dependency, not by effort. The two steps that get skipped are the chargeback label and the attribute pruning, and both get rediscovered a quarter later — the first when finance asks for a split nobody can produce, the second during a data protection review.

One detail worth knowing before you debug a silent collector: Claude Code does not pass OTEL_ variables to the subprocesses it spawns, including the Bash tool, hooks, MCP servers and language servers. Instrumentation you expected to inherit will not.

The artefact

The ten steps

  1. Decide the identity question first. Team-level attribution or per-developer attribution is a policy decision, not a configuration one, and it determines what you are allowed to store. Everything below changes depending on the answer.
  2. Stand up the collector before enabling any client. Point it at a metrics backend you already operate, and terminate TLS properly — the OTLP endpoint will carry a bearer token in OTEL_EXPORTER_OTLP_HEADERS.
  3. Push managed settings to every machine, not a wiki page telling developers to export variables. Setting OTEL_EXPORTER_OTLP_ENDPOINT centrally also removes conflicting developer-set per-signal endpoints at startup, and logs a warning you can see with claude --debug.
  4. Set OTEL_RESOURCE_ATTRIBUTES with the team, department or cost centre you intend to charge back to. Keep the values low-cardinality: every custom key becomes a label on every metric series, and a per-project label on a large team is how a metrics bill starts competing with the token bill.
  5. Turn off the attributes you decided not to keep. OTEL_METRICS_INCLUDE_ACCOUNT_UUID and OTEL_METRICS_INCLUDE_SESSION_ID both default to true, and session ID in particular is high cardinality by design.
  6. Leave content logging alone unless legal has signed it. OTEL_LOG_USER_PROMPTS, OTEL_LOG_TOOL_DETAILS, OTEL_LOG_TOOL_CONTENT and OTEL_LOG_RAW_API_BODIES all default to disabled, and each one moves source code and prompt text into your logging pipeline.
  7. Provision an Admin API key and pull the Analytics API daily into the same warehouse as the metrics. Anthropic states it is free to use for all organisations with access to the Admin API. It is not the only per-user cost view: API customers see per-user spend for the current month in the Console dashboard at platform.claude.com/claude-code, and Team and Enterprise plans export a per-user, per-model spend report as CSV from Settings → Analytics. The Analytics API is the one you can schedule into a warehouse, which is why it is the one on this list.
  8. Reconcile weekly against the Cost API. The OpenTelemetry number is an estimate; the cost report is what finance will see. Track the gap as a percentage and investigate when it moves, not when it is non-zero.
  9. Record the baseline before anyone tunes anything. Model routing, caching and prompt changes all land after the measurement starts, and without a baseline you cannot attribute a saving to any of them.
  10. Write down the denominators. Cost per what, over which window, counting which people — before the first chart exists, not after somebody disputes it.

The managed settings file

The managed settings file below is the whole client-side configuration, and every key in it comes from Anthropic's monitoring reference at code.claude.com/docs/en/monitoring-usage. The last two lines are the team-attribution decision expressed as configuration: both of those attributes default to true, so switching them off is an active choice that has to be made once, centrally, rather than negotiated per machine. Note that user.email is still attached whenever it is available and has no opt-out flag, which is why the collector remains the enforcement point rather than the client.

{
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "OTEL_METRICS_EXPORTER": "otlp",
    "OTEL_LOGS_EXPORTER": "otlp",
    "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "https://otel.internal.example.com:4317",
    "OTEL_RESOURCE_ATTRIBUTES": "department=engineering,team.id=platform,cost_center=eng-123",
    "OTEL_METRICS_INCLUDE_ACCOUNT_UUID": "false",
    "OTEL_METRICS_INCLUDE_SESSION_ID": "false"
  }
}

Attributing spend to a team without identifying a person

Per-developer cost data is easy to collect and hard to keep. Claude Code attaches user.id always, user.email whenever it is available, and user.account_uuid by default, so the raw telemetry stream identifies individuals unless you decide otherwise. In a German or Austrian organisation that stream is performance data about named employees, and a works council will treat it as such.

Our default is team-level aggregation at the collector, with per-user attribution kept only where an agreement already covers it. Not because per-user data is useless — it is the fastest way to find the engineer who has quietly solved prompt caching for everyone else — but because a telemetry stack that identifies individual engineers gets switched off, and a switched-off stack measures nothing.

The Analytics API forces the same conversation from the other end, because it has no team-level mode. Every record carries an actor: either a user_actor with an email_address, or an api_actor with an api_key_name. If per-user identification is off the table, aggregate on ingest and never persist the raw response — the API will keep returning it, so the control has to live in your pipeline.

There is a legitimate middle position worth naming. Keep per-user data at full fidelity for a fixed, short retention window, aggregate to team level after it, and document both. That preserves the debugging value of individual data without accumulating a permanent record of how much each engineer costs, which is the thing nobody wants to explain in a meeting.

Five numbers that will mislead your board

Every metric on the list below is real, exported by Anthropic, and wrong for the purpose it usually gets used for. None of them is a bug. They measure what they say they measure, and then get put on a slide under a heading they do not support.

The fifth is the one that survives review, because it looks like completeness.

  • Lines of code. claude_code.lines_of_code.count carries type=added and type=removed, and counts what the agent wrote — including code reverted ten minutes later. It is throughput of output, not delivered work. Join to your version control system for merge status before it goes anywhere near a productivity claim.
  • Cost on a subscription seat. The field is called estimated_cost for a reason, and customer_type distinguishes api from subscription. For subscription customers the seat is billed flat, so a per-user dollar figure is a notional allocation with no matching invoice line. Compare it across users; do not add it up and call it spend.
  • Tool acceptance rate. claude_code.code_edit_tool.decision records a permission decision, not a correctness judgement, and its source attribute includes config alongside user_permanent and user_temporary. Decisions made by configuration were never made by a human, so a rising acceptance rate can just mean somebody widened the allowlist.
  • The mean cost per developer. One average across a team hides whether the spend is one heavy user or forty even ones, and those two situations need opposite responses. Report the median and the top decile next to the mean, or do not report a single figure at all.
  • Total spend from the Analytics API. It only covers Claude Code on the Claude API. Bedrock, Microsoft Foundry, Google Cloud and Claude Platform on AWS are excluded, so in a mixed estate the number is not an estimate of the total — it is a complete count of a subset, presented as if it were everything.

Turning eight metrics into one figure a CFO recognises

The eight metrics exist so you can compute three ratios, and the ratios are what a budget conversation is actually about. None of them requires a number from us; all of them require a denominator you have to choose and write down.

Cost per merged pull request is the honest headline. Take claude_code.cost.usage summed over the window, and divide by merged pull requests from your version control system — not by pull_requests_by_claude_code, which counts what was created rather than what landed. The gap between those two denominators is itself worth watching.

Cost per active hour is the ratio that converts into an FTE comparison. claude_code.active_time.total is in seconds and carries type=user and type=cli, so user-attributed active time divided into cost gives a dollar-per-hour figure you can hold against your own loaded engineering rate. We are not supplying that rate — every organisation's is different and most already know theirs to the euro.

Cost per developer per month is the one everybody asks for and the one to publish last, because it is the most sensitive to who counts as a developer. Distinct actors with at least one session is a defensible denominator. Headcount in the engineering org is not, and using it is how a tool that is cheap per user gets reported as expensive per seat.

Run all three for a full quarter before drawing a trend. Thirteen weeks covers enough release cycles, holiday weeks and model changes that the curve means something. Four weeks measures the novelty period.

Denominators

# Client-side metric reference:
# https://code.claude.com/docs/en/monitoring-usage
#
# Per-user daily aggregates. Free, Admin API key required.
# https://platform.claude.com/docs/en/manage-claude/claude-code-analytics-api
curl -sS "https://api.anthropic.com/v1/organizations/usage_report/claude_code?starting_at=2026-09-01&limit=1000" \
  -H "anthropic-version: 2023-06-01" \
  -H "x-api-key: $ANTHROPIC_ADMIN_KEY"

# The reconciliation source. Daily buckets only; group by workspace.
# https://platform.claude.com/docs/en/manage-claude/usage-cost-api
curl -sS "https://api.anthropic.com/v1/organizations/cost_report?starting_at=2026-09-01T00:00:00Z&ending_at=2026-10-01T00:00:00Z&group_by[]=workspace_id&group_by[]=description" \
  -H "anthropic-version: 2023-06-01" \
  -H "x-api-key: $ANTHROPIC_ADMIN_KEY"

# Denominators, decided before the first chart:
#   cost per merged PR   = sum(claude_code.cost.usage) / merged PRs from git
#   cost per active hour = sum(claude_code.cost.usage)
#                          / (sum(claude_code.active_time.total{type="user"}) / 3600)
#   cost per developer   = sum(claude_code.cost.usage)
#                          / count(distinct actors with num_sessions > 0)

The strongest argument against measuring any of this

Do not instrument. Buy the seats, cap the spend with a budget limit, and spend the engineering weeks on something that ships. Nobody demands per-developer telemetry for the IDE licence, the CI minutes or the observability contract, and all three are real money.

That argument is better than it sounds, and for a team of ten it usually wins. The telemetry stack has a running cost — a collector, a metrics backend, cardinality you have to manage, a pipeline that strips personal data — and below a certain spend that cost is a meaningful fraction of the thing it measures.

It stops winning at two specific moments. The first is when finance asks which cost centre the invoice belongs to and the honest answer is that nobody can tell. The second is when someone proposes an optimisation — routing cheap steps to a smaller model, restructuring prompts for cache hits, moving overnight work to batch — and there is no baseline to prove whether it worked. Optimisation without measurement is faith, and it is usually faith in whatever the last vendor deck claimed.

So the real question is not whether to measure but when to start, and the answer is one release before you need the answer, because a baseline cannot be collected retroactively.

What you have after a quarter of this

A cost per merged pull request with a stated denominator, a per-team split that came from a label rather than an argument, a reconciliation gap between your estimate and Anthropic's cost report that you can explain, and a baseline that makes the next optimisation provable instead of plausible.

You will also have found at least one thing you were not looking for. In every cost instrumentation project we have run — across LLM workloads generally, not Claude Code specifically — the surprise has never been the headline number. It has been the distribution underneath it.

What you will not have is our figure, and you do not want it. You want yours, measured on your repositories, with your model mix, over a window long enough that the next model release does not invalidate it.

Questions we get asked about measuring Claude Code cost

How do we measure what Claude Code costs per developer?

Two data paths, and a real answer needs both. Claude Code's OpenTelemetry exporter emits claude_code.cost.usage in USD with user and model attributes, which gives near-real-time attribution against a collector you run. The Claude Code Analytics API returns one aggregated record per user per UTC day with token counts and an estimated cost per model. Use the exporter for dashboards and alerts, the Analytics API for the monthly figure, and reconcile both against the Admin Cost API.

Which metrics does Claude Code actually export?

Eight, as listed in Anthropic's Claude Code monitoring reference: claude_code.session.count, claude_code.lines_of_code.count, claude_code.commit.count, claude_code.pull_request.count, claude_code.cost.usage in USD, claude_code.token.usage in tokens, claude_code.code_edit_tool.decision, and claude_code.active_time.total in seconds. Everything a finance team asks for — cost per pull request, cost per active hour — is arithmetic performed on those eight inside your own metrics backend.

Does the Claude Code Analytics API cover usage on Bedrock or Vertex?

No. Anthropic states that the Claude Code Analytics API tracks Claude Code usage on the Claude API only, and that usage through Claude in Amazon Bedrock, Claude in Microsoft Foundry, Claude on Google Cloud or Claude Platform on AWS is not included. If one business unit runs Claude Code against Bedrock, the per-user report is quietly incomplete rather than visibly wrong, which is the more expensive failure mode.

Can we attribute Claude Code spend to a team without identifying individual developers?

Yes, and that version is usually the only one that survives a works council. Set a team or cost-centre label through OTEL_RESOURCE_ATTRIBUTES, aggregate on that label at the collector, and drop the per-user attributes before anything is written to storage. Claude Code attaches user.email whenever it is available and includes user.account_uuid by default, so the collector — not the developer's machine — is where that decision has to be enforced.

How fresh is Claude Code cost data?

It depends which path you read, and the three do not agree. OpenTelemetry metrics export on OTEL_METRIC_EXPORT_INTERVAL, which defaults to 60000 milliseconds. The Claude Code Analytics API is daily and deliberately excludes data younger than one hour so cursor pagination stays stable. Admin usage and cost data typically appears within five minutes of a request completing. No path gives a live per-keystroke figure.

Why does this page not publish a euro figure per developer per month?

Because we do not have ninety days of our own data yet, and a figure without the measurement window, model mix and team profile behind it is decoration. Cost per developer moves with model choice, cache hit rate, how many turns a task takes and whether engineers run agents in parallel. The design described here produces your number on your estate. It is not transferable from ours or from anyone else's blog post.

Next step

Get the measurement running before the budget conversation

Two weeks, fixed price. We stand up the collector, push managed settings, wire the Admin API pulls into your warehouse and define the denominators with your finance team. You end with a working baseline and a dashboard nobody has to argue about — not a benchmark borrowed from someone else's estate.