# Claude Code Cost Tracking — What Exists, What's Missing, and How to Meter Every Session

Claude Code shows an estimated session cost, a status-line figure, and OpenTelemetry metrics. None of them price a call, split the loop from the leaf work, or hold on a subscription. The reference: what /usage, the status line, OTel, and the transcripts give you, what they can't, and the one env var that meters every session.

<div class="acp-shot-frame">
<img src="/assets/img/screenshots/session-cost-xray.png" alt="Session cost X-ray of a real working day: $472.03 at API rates, 1,052 loop turns, 100% loop tax at a 100% cache hit rate, the cumulative bill curve, and 3,744 free tool calls beneath it — with 4,790 allowed, 6 denied, 115 PII findings" style="width:100%;height:auto;border:1px solid var(--line-2);border-radius:10px;box-shadow:0 20px 50px -24px rgba(0,0,0,0.9);margin:8px 0;" />
</div>

<div style="margin:8px 0 28px;padding:20px 22px;border:1px solid var(--line-2);border-radius:12px;background:var(--color-accent-light,#f0effe);">
  <p style="margin:0 0 12px;font-size:15px;line-height:1.6;color:var(--acp-text);"><strong>Just want the answer?</strong> Claude Code estimates a session total; it doesn't price calls. The ACP hook does, from the transcript Claude Code already writes:</p>
  <pre data-track="CCCost: Hero Config Copy" style="margin:0 0 12px;background:var(--color-surface,#faf9ff);border:1px solid var(--line-2);border-radius:8px;padding:12px 14px;overflow-x:auto;"><code>curl -sf https://agenticcontrolplane.com/install.sh | bash
claude   # every model turn priced from the transcript; session X-ray in the console</code></pre>
  <p style="margin:0 0 12px;font-size:15px;line-height:1.6;color:var(--acp-text);">Optional: launch with <code>claude-acp</code> to also route model calls through the proxy &mdash; on exit it prints the session total with a link to the breakdown:</p>
  <pre style="margin:0 0 12px;background:var(--color-surface,#faf9ff);border:1px solid var(--line-2);border-radius:8px;padding:12px 14px;overflow-x:auto;"><code>ACP · session: 276 model calls · 1,697 tool calls · $148.16 @ API rates
→ https://cloud.agenticcontrolplane.com/sessions/…</code></pre>
  <p style="margin:0;font-size:13px;color:var(--acp-text-dim);"><a href="/docs/setup#i-use-claude-code" data-track="CCCost: Setup Guide" style="font-weight:600;">Full Claude Code setup (both planes) →</a> &nbsp;·&nbsp; <a href="https://cloud.agenticcontrolplane.com" data-track="CCCost: Console Signup">get a workspace key →</a> &nbsp;·&nbsp; free up to 5 agents</p>
</div>

Claude Code is better at this than most harnesses. It will tell you a session's estimated cost, put a dollar figure in your status line, and emit a cost metric over OpenTelemetry. What it won't do is price a single call, tell you which part of the session the money went to, or produce a number that means anything on a Max subscription.

This is the reference for what you can see natively, what each surface can't tell you, and the config that closes the gap.

## What Claude Code shows natively

- **`/usage`** &mdash; the Session block at the top shows total estimated cost, API duration, and usage by model for the current session. On Pro, Max, Team and Enterprise plans it also shows plan-usage bars and an attribution breakdown (skills, subagents, plugins, MCP servers). The docs are plain that the session cost figure is meant for API users; on a subscription it "isn't relevant for billing." Older builds called this `/cost`.
- **The status line** &mdash; a `statusLine` script receives JSON on every refresh with `cost.total_cost_usd`, `cost.total_duration_ms`, `cost.total_api_duration_ms`, `context_window.used_percentage`, rate-limit percentages on subscription plans, and a `prompt_cache` block after the first response. One cumulative number per session, updated as it grows.
- **OpenTelemetry** &mdash; set `CLAUDE_CODE_ENABLE_TELEMETRY=1` plus the `OTEL_*` exporter variables and Claude Code emits `claude_code.cost.usage` (USD) and `claude_code.token.usage` (split by input, output, cache read, cache creation), tagged with model. With the logs exporter on, it also emits `claude_code.tool_result` and `claude_code.tool_decision` events per tool call. This is the most complete native surface, and it needs a collector on the other end.
- **The session transcripts** &mdash; every session writes a JSONL file under `~/.claude/projects/`. Community tools such as ccusage read those files and total the token counts against a price list. The schema isn't documented, so those tools track the format rather than an API.

So the native answer to "what did that session cost?" is a session total, estimated, with a caveat on subscriptions. Better than nothing; not attribution.

## What a session total can't tell you

1. **Which calls the money went to.** A session is a few hundred model calls. The total says $148.16; it doesn't say that the last 28 turns bought 10% of the output, or that one re-read of a large file cost more than the edit it preceded. That needs a price on each call at the moment it's made.
2. **Loop vs. leaf.** In agent sessions the bill is mostly the orchestration loop re-reading its own context to pick the next step, not the leaf work that produces answers. In the July research corpus (285,814 metered calls across our own workspaces) the loop was 97% of spend. A token total can't separate the two; per-call tagging can, and it changes which model you put on the loop.
3. **Cache economics per call.** Cached input bills at a fraction of the full rate, so two sessions with the same token count can differ several-fold in dollars. The status line's `prompt_cache` block gives you the session's shape; only per-call metering shows the turn where the prefix stopped being cache-stable.
4. **The fleet.** Native surfaces are per-machine and per-session. Cost by agent, cost by person, and run-to-run variance across a team live nowhere in Claude Code.
5. **A cap that holds.** There is no native budget. A runaway loop surfaces on next month's statement, or in the rate-limit bar after the money is gone.

## The config

There are two ways to get per-call cost, and the first needs nothing but the hook.

**From the transcript (default).** Every PostToolUse hook call carries `transcript_path`, and the session JSONL records each assistant turn's `input_tokens`, `cache_read_input_tokens`, `cache_creation_input_tokens`, `output_tokens` and model. The installed ACP hook reads the turns it hasn't reported yet, sends them with the tool-output report it already makes, and the gateway prices each one at list rates with the cache rates applied. Plain `claude`, no launcher, no env var; on a subscription the figures are API-rate equivalents. Turns land beside the tool calls as loop turns, so the Session X-ray, loop-vs-leaf split and the daily ledger see them the same way they see proxied calls.

**Through the proxy (optional).** The proxy adds what a transcript can't give you: policy on the model call itself (denied tool_use blocks stripped before the harness sees them) and the declared tool surface, captured from request bodies. Claude Code honors `ANTHROPIC_BASE_URL`. Point it at the ACP proxy and pass your workspace key as the auth token:

```bash
# ~/.zshrc, or the environment of whatever launches claude
export ANTHROPIC_BASE_URL="https://api.agenticcontrolplane.com/anthropic"
export ANTHROPIC_AUTH_TOKEN="$ACP_KEY"   # workspace key (gsk_…)
```

The one-command installer writes this for you as a launcher, `~/.acp/bin/claude-acp`; plain `claude` keeps its normal model path and is still priced from the transcript. Either way each `/v1/messages` request passes through the proxy carrying the login you already have: a Max or Pro OAuth session stays subscription traffic, an API key stays API traffic. The usage fields on the way back are priced at list rates, and the call lands as a row in [the console](https://cloud.agenticcontrolplane.com) &mdash; model, tokens, cached share, dollars, and whether it was a loop turn or leaf work.

When a `claude-acp` session exits it prints the session's bill and a link to its cost X-ray:

```
ACP · session: 276 model calls · 1,697 tool calls · $148.16 @ API rates
→ https://cloud.agenticcontrolplane.com/sessions/…
```

That line is from a real working day on a Max subscription; [the page it links to](/for-coding-agents) shows the curve.

## Subscription and API-key billing

The proxy never changes who pays. A subscription login is forwarded untouched and Anthropic bills the subscription as before; ACP labels every dollar figure for that traffic as an API-rate equivalent, which is what the same tokens would have cost through the API, not a charge. API-key traffic is billed by Anthropic at standard rates. ACP does not touch or mark up your tokens.

## Budget limits

Claude Code has none. Through the proxy, **workspace-billed** traffic is subject to your workspace's daily LLM cost cap, enforced at the gateway before the call goes upstream; the session halts rather than warns. **Subscription and bring-your-own-key** traffic is billed or quota-limited by Anthropic; ACP meters it but cannot enforce a cap on an account it doesn't hold.

## Troubleshooting

**Calls work but nothing appears in the console.** Check `ANTHROPIC_AUTH_TOKEN` is your ACP key, not an Anthropic key. The proxy needs the workspace key to attribute the call; without it the request is rejected rather than metered to nowhere.

**`/usage` and the console disagree.** They measure different things. `/usage` is Claude Code's own estimate for the session; the console prices each call from the usage fields the API returned. On a subscription, only the console figure is labelled as an API-rate equivalent.

**The status line shows cost but the console shows nothing.** The status line reads Claude Code's internal estimate and works without a proxy. Console rows need the base URL set in the environment of the process that launched `claude`; a value exported in one shell doesn't reach an IDE-launched session.

**OTel metrics stopped when I set the base URL.** Unrelated: the docs note `ANTHROPIC_BASE_URL` is not passed to spawned subprocesses, but telemetry export is configured by the `OTEL_*` variables, which are. Check the collector endpoint first.

## What this pairs with

Cost is one of the two planes. The other &mdash; controlling what Claude Code *does* &mdash; is the PreToolUse hook covered in the [Claude Code hooks reference](/blog/claude-code-hooks-reference). They're independent: the hook sees tool calls and never token usage; the proxy sees model calls and never what your shell actually ran. [Ways to set up ACP](/docs/setup#i-use-claude-code) wires both and tells you which planes you have.

## Frequently asked questions



## Where to read more

- [Claude Code hooks reference](/blog/claude-code-hooks-reference) &mdash; the control plane: events, decisions, scopes, what survives bypass mode
- [Claude Code cost tracking: token counters tell you what you spent, not where it went](/blog/claude-code-cost-tracking) &mdash; the argument behind this reference, with the $148.16 day
- [The loop tax](/blog/the-loop-tax) &mdash; why most agent spend sits in the orchestration loop
- [Codex CLI cost tracking](/blog/codex-cli-cost-tracking) &mdash; the sibling reference for Codex
- [Claude Code docs: manage costs](https://code.claude.com/docs/en/costs) and [monitoring usage](https://code.claude.com/docs/en/monitoring-usage) &mdash; the upstream references for `/usage` and OpenTelemetry
