Claude Code OpenTelemetry: the variables, the metrics, and what the stream never carries
The variables that export Claude Code metrics to your collector, which attributes name a person, the one repository field, and what the stream never carries.
Set CLAUDE_CODE_ENABLE_TELEMETRY=1, name an exporter and an OTLP endpoint, and Claude Code streams eight metrics and 28 kinds of event to a collector you run: cost, tokens, sessions, lines, commits, pull requests, edit decisions and active time, each tagged with the session and, when signed in, the user's email. This page is the variable-level how-to, from Anthropic's monitoring page read on 30 October 2026: what to set, what arrives, which attributes name a person, the one field that names a repository, and what the stream never carries.
Turn Claude Code telemetry on: the variables
Claude Code reads the standard OpenTelemetry exporter variables plus one of its own. The quick start on Anthropic's monitoring page, in the order it gives them:
export CLAUDE_CODE_ENABLE_TELEMETRY=1 export OTEL_METRICS_EXPORTER=otlp export OTEL_LOGS_EXPORTER=otlp export OTEL_EXPORTER_OTLP_PROTOCOL=grpc export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your-token"
CLAUDE_CODE_ENABLE_TELEMETRYis required; without it the other variables do nothing.- The exporters.
OTEL_METRICS_EXPORTERtakesconsole,otlp,prometheus,none;OTEL_LOGS_EXPORTERtakesconsole,otlp,none. Both are optional: configure the signal you want, andnoneturns one off. - The protocol.
grpc,http/json,http/protobuf, and "Claude Code has no default protocol, so set this or the signal-specific protocol variable for eachotlpexporter you enable".OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,OTEL_EXPORTER_OTLP_LOGS_ENDPOINTand the_PROTOCOLpair override the generic variable for one signal; per-signal headers merge with the generic ones. - The intervals.
OTEL_METRIC_EXPORT_INTERVALdefaults to 60,000 ms andOTEL_LOGS_EXPORT_INTERVALto 5,000 ms. Lower them to debug, put them back for production. - The check.
claude_code.session.countarrives when a session starts; for a logs-only setup, send a prompt and look forclaude_code.user_prompt. If nothing arrives, runclaude --debug-file <path>: your exporters' failures are prefixed[3P telemetry], and lines prefixed[Anthropic telemetry]are Anthropic's own operational telemetry, a separate stream. - Once per launch. The variables are read at startup: "a feature that reads its variables once at startup, such as OpenTelemetry monitoring, keeps its startup values until you relaunch."
For every machine, the same keys go in the env block of managed settings. Anthropic's example:
{ "env": { "CLAUDE_CODE_ENABLE_TELEMETRY": "1", "OTEL_METRICS_EXPORTER": "otlp", "OTEL_LOGS_EXPORTER": "otlp", "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", "OTEL_EXPORTER_OTLP_ENDPOINT": "http://collector.example.com:4317", "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer example-token" } }
The file is managed-settings.json at /Library/Application Support/ClaudeCode/managed-settings.json on macOS, /etc/claude-code/managed-settings.json on Linux and WSL and C:\Program Files\ClaudeCode\managed-settings.json on Windows, placed by whatever already puts files on the fleet; an MDM profile or server-managed settings from the claude.ai admin console deliver the same keys. Three rules from the page:
- A repository cannot turn it on. "Claude Code ignores the OpenTelemetry exporter variables in a repository's
.claude/settings.jsonand.claude/settings.local.json, so a repository can't use them to turn telemetry on, choose where it goes, or capture content." A developer's shell or~/.claude/settings.jsoncan; a repository can only set an exporter tonone. - Managed settings pin the destination. Endpoints: "when you set
OTEL_EXPORTER_OTLP_ENDPOINT, Claude Code removes every developer-set per-signal endpoint." Protocols and credentials the same way. "This removal behavior changes where telemetry is delivered, not what Claude Code collects." - Subprocesses do not inherit it. "Claude Code doesn't pass
OTEL_*environment variables to the subprocesses it spawns, including the Bash tool, hooks, MCP servers, and language servers."
The metrics: eight counters
With OTEL_METRICS_EXPORTER set, Claude Code exports eight metrics under the meter com.anthropic.claude_code, delta temporality by default, from a service named claude-code in a terminal and claude-code-desktop from the Claude Desktop app's Code tab. Each carries the standard attributes of the next section; the table lists what each adds.
| Metric | Counts | Beyond the standard attributes |
|---|---|---|
session.count | Count of CLI sessions started | start_type: fresh, resume, continue or agents_view |
lines_of_code.count | Count of lines of code modified | type: added or removed; model |
pull_request.count | Number of pull requests created | the standard attributes only |
commit.count | Number of git commits created | the standard attributes only |
cost.usage | Cost of the Claude Code session, in USD | model, query_source, speed, effort, and the agent, skill, plugin and MCP names |
token.usage | Number of tokens used, in tokens | type: input, output, cacheRead or cacheCreation; then as the cost counter |
code_edit_tool.decision | Count of code editing tool permission decisions | tool_name, decision, source, language |
active_time.total | Total active time, in s | type: user or cli |
input type excludes cache reads and writes, which are the cacheRead and cacheCreation types.Two things to know about the dollars. "Cost metrics are approximations. For official billing data, refer to your API provider (Claude Console, Amazon Bedrock, or Google Cloud's Agent Platform)." And they are list price: "By default, Claude Code computes every cost figure it shows developers at list price, so if your organization pays contracted rates, the figures in /usage, the status line, and OpenTelemetry don't match your bill." The modelPricing managed setting (Claude Code v2.1.242 or later) changes what Claude Code reports, not what Anthropic charges. Some of the agent, skill, plugin and MCP names on the cost and token counters, the user-defined agents, third-party plugins and their skills and user-configured MCP servers, are redacted to custom or third-party unless OTEL_LOG_TOOL_DETAILS=1 is set.
The events: what each carries
With OTEL_LOGS_EXPORTER set, Claude Code logs 28 kinds of event, counted on the page on 30 October 2026. Each carries the standard attributes, an ISO timestamp, a per-process sequence number and prompt.id, which ties every event one prompt caused to that prompt. The five most queried:
claude_code.user_prompt—prompt_length;prompt, redacted unlessOTEL_LOG_USER_PROMPTS=1;command_namewhen the prompt was a/command.claude_code.tool_result—tool_name,success,duration_ms,error_type, the input and result sizes in bytes, the permissiondecision_source; withOTEL_LOG_TOOL_DETAILS=1,tool_parameterswith the Bash command andtool_inputwith file paths and arguments.claude_code.api_request—model,cost_usd,duration_ms,input_tokens,output_tokens,cache_read_tokens,cache_creation_tokens,request_id,speed,effort,query_source.claude_code.api_error—model,error,status_code,duration_ms,attempt; logged once, after the retries are spent.claude_code.tool_decision—tool_name,decision(accept or reject),source(config, hook, user_permanent, user_temporary, user_abort, user_reject),permission_mode, and the auto-modeclassifier_verdict.
The rest: assistant_response (length only, unless OTEL_LOG_ASSISTANT_RESPONSES=1), API refusals, the raw API request and response bodies (only with OTEL_LOG_RAW_API_BODIES), safety checks, permission-mode changes, sign-ins, MCP connections, plugins, skills, @ mentions, hooks, exhausted retries, internal errors, compaction, finished subagents, the feedback survey, the retention sweep and resolved managed settings. "Raw file contents and code snippets are not included in metrics or events." "User prompt content is not collected by default. Only prompt length is recorded."
Which attributes name a person
Every metric and event carries the standard attributes, and by default they identify the person: the signed-in email, the account, the organization and the session.
| Attribute | Carries, and what controls it |
|---|---|
user.email | the sign-in email; Always included when available |
user.id | a random id kept in ~/.claude.json; Always included |
user.account_uuid | the account UUID; OTEL_METRICS_INCLUDE_ACCOUNT_UUID, default true |
user.account_id | the account id in the admin APIs' format; OTEL_METRICS_INCLUDE_ACCOUNT_UUID, default true |
organization.id | the organization UUID; Always included when available |
session.id | the session, replaced by /clear; OTEL_METRICS_INCLUDE_SESSION_ID, default true |
terminal.type | iTerm.app, vscode, cursor, tmux; Always included when detected |
app.version and app.entrypoint are off by default and join with OTEL_METRICS_INCLUDE_VERSION=true and OTEL_METRICS_INCLUDE_ENTRYPOINT=true.- The email has no switch.
user.emailis "Always included when available". Anthropic's page: "When authenticated via OAuth,user.emailis included in telemetry attributes, sent only to the OTel endpoint you configure, never to Anthropic. If this is a concern for your organization, work with your telemetry backend to filter or redact this field". The processor below does that. - Two switches exist.
OTEL_METRICS_INCLUDE_ACCOUNT_UUID=falsedropsuser.account_uuidanduser.account_id;OTEL_METRICS_INCLUDE_SESSION_ID=falsedropssession.id. "Lower cardinality generally means better performance and lower storage costs but less granular data for analysis." user.idstays, and is not the person. "Random anonymous identifier generated on first run and persisted in~/.claude.json. It contains no personal information and is not derived from your Claude account."- Your own labels ride along.
OTEL_RESOURCE_ATTRIBUTES=department=platform,team.id=42puts those keys on every datapoint (OTEL_METRICS_INCLUDE_RESOURCE_ATTRIBUTES, default true). On a Claude apps gateway sign-in the stream also carriesuser.groups.
The page's own OpenTelemetry Collector example deletes the prompt attributes; the same attributes processor with the email as its key removes it before anything is stored:
processors: attributes/drop-email: actions: - key: user.email action: delete
The one repository field: OTEL_METRICS_INCLUDE_REPOSITORY
Since Claude Code v2.1.269, OTEL_METRICS_INCLUDE_REPOSITORY=true adds four attributes to metrics and events; the default is false. "Claude Code derives these attributes once per session from the repository's origin remote."
| Attribute | Value |
|---|---|
vcs.repository.url.full | the browser URL, without .git |
vcs.owner.name | the owner or group path; omitted for a single-segment path |
vcs.repository.name | the bare repository name |
vcs.provider.name | github, gitlab, bitbucket, gitea when recognised; omitted otherwise |
Values are lowercased, with no credentials, query strings or fragments. "The attributes are omitted when the session has no origin remote, when the remote isn't URL-shaped, or when the only enclosing repository is your home directory." A vcs.* key in OTEL_RESOURCE_ATTRIBUTES replaces the derived value. "The attributes flow only to your own exporters; Anthropic's telemetry drops every vcs.* key."
It names the remote, not the directory: a session opened at the root of a monorepo tags every service's work with the monorepo. With OTEL_LOG_TOOL_DETAILS=1, a successful git commit run by the Bash tool adds vcs.ref.head.revision and vcs.ref.head.name to its tool_result event, the commit and the branch; the pull request counter still carries nothing but the standard attributes.
What the stream never carries
Read against the monitoring page on 30 October 2026.
A plan-window reading. No metric or event on the page carries the five-hour or seven-day window; the page's one mention of a rate limit is the auto-mode classifier failing on one. The counters say what a session consumed, not what is left. Caprock keeps that reading from the same machine, hourly; 13 to 21 October 2026 on my Mac:
- 5%
- 13 October, 00:00, the window's first reading
- 99%
- 19 October, 07:00, after 6 days of climbing
- 1%
- 19 October, 16:00, after the reset
A pull request's identity. claude_code.pull_request.count is "Incremented when Claude Code creates a pull request or merge request through a shell command or an MCP tool." It carries the standard attributes only: no number, URL, branch or merge state, so the stream cannot say what a merged pull request cost.
Sessions the configuration did not reach. "OpenTelemetry export to your backend is opt-in and requires explicit configuration." Each process exports according to its own environment and settings files: a laptop the policy does not cover, a cloud session without the variables, a terminal with OTEL_METRICS_EXPORTER=none sends nothing, and the collector has no row saying so. A recorder on the machine has the sessions whichever way they were started. 29 September to 28 October 2026, one developer's Mac:
- 626
- sessions started from Caprock
- 1,737
- started in a terminal or elsewhere, recorded all the same
A charge. The cost counter is list price, as the costs page says above. On a Pro, Max or Team seat the figure is what the tokens would have cost on an API key, not what was billed; on Bedrock or Vertex the bill is your cloud's.
Claude Code on Bedrock, Vertex or Foundry
Anthropic's costs page, read 30 October 2026: "Claude Code does not send metrics from your cloud back to Anthropic, so the analytics dashboards and the Claude Code Analytics API do not cover this usage." The same page: "OpenTelemetry export works on every setup and is the only option that streams per-user token and cost metrics into your own observability stack in near real time." Anthropic's own operational telemetry is off there by default ("By default, error reporting, telemetry, and bug reporting are disabled when using Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry, or Claude Platform on AWS."); the export to your collector is the same variables, set on each machine or through managed settings, and on Bedrock the request_id on API events comes from the x-amzn-requestid header. Anthropic's analytics page sends admins who want per-user token counts to this export.
Beside the collector: Caprock
Caprock, a free desktop app, reads the files the monitoring page itself names, the ~/.claude/projects/*/*.jsonl files, on the machine: every Claude Code session, with Codex and OpenCode beside it, whether or not an environment variable was set and whoever started it. Each turn is priced at list from a dated table, each session sits in its repository's row by working directory, and the repository's cost is divided by the pull requests merged in the window: cost per merged pull request, the figure the stream has no field for. The five-hour and seven-day windows are read as Claude Code reports them; the three readings above are from that record. Nothing leaves the machine: no collector, no account, no plan.
Caprock for Teams is the collector's counterpart for a team: each machine sends aggregates by work unit, per repository, pull request, release and week, to a server you run, with no field for a prompt, a reply or a command's output; the person is a switch, off by default. Run it beside the OpenTelemetry stream: the collector keeps the per-user token series it was designed for, the ledger keeps cost per pull request however you pay. Buying Caprock is one flat price for the team.
The local tools that show one machine's usage without a collector: Claude Code usage monitors. The window on the status line: Claude Code status line. The comparison across Anthropic's dashboard, spend report and APIs: Claude Code analytics.
Questions people ask
- What is Claude Code OTel?
- Claude Code's OpenTelemetry export. Set CLAUDE_CODE_ENABLE_TELEMETRY=1 and the OTEL_* exporter variables and it streams eight metrics (cost, tokens, sessions, lines of code, commits, pull requests, edit decisions, active time) and 28 kinds of event to a collector you run. It is off until configured. Read 30 October 2026.
- Does Claude Code send telemetry to Anthropic?
- Two separate streams. The OpenTelemetry export goes only to the endpoint you configure, never to Anthropic, the monitoring page says. Separately, on the Claude API Claude Code sends Anthropic operational metrics by default (latency, reliability and usage patterns, never code, prompts or file paths); DISABLE_TELEMETRY=1 turns that off, and it is off by default on Bedrock, Vertex and Foundry.
- How do I send Claude Code metrics to Datadog or Grafana?
- Any OTLP receiver works: set OTEL_EXPORTER_OTLP_PROTOCOL (grpc, http/protobuf or http/json), OTEL_EXPORTER_OTLP_ENDPOINT and, if the backend needs one, OTEL_EXPORTER_OTLP_HEADERS; OTEL_METRICS_EXPORTER=prometheus exposes a scrape instead. The monitoring page names no vendor. Confirm with the claude_code.session.count metric.
- Does Claude Code telemetry include the user's email?
- Yes, when signed in: user.email is always included when available, with no variable to drop it; Anthropic's advice is to filter or redact it in your backend, and an OpenTelemetry Collector attributes processor with action delete does that. OTEL_METRICS_INCLUDE_ACCOUNT_UUID=false and OTEL_METRICS_INCLUDE_SESSION_ID=false drop the account and session ids.
- How do I disable Claude Code telemetry?
- For the export to a collector, leave CLAUDE_CODE_ENABLE_TELEMETRY unset, or set OTEL_METRICS_EXPORTER=none and OTEL_LOGS_EXPORTER=none; a repository's settings file may set none even though it cannot turn telemetry on. For Anthropic's own operational telemetry, set DISABLE_TELEMETRY=1, or CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 for every non-essential call, in the shell or the env block of managed settings.
- Can OpenTelemetry show Claude Code cost per repository?
- Per session repository, with OTEL_METRICS_INCLUDE_REPOSITORY=true on Claude Code v2.1.269 or later: vcs.repository.name and its owner, URL and provider from the origin remote, off by default and dropped by Anthropic's own telemetry. The query is yours to write, and nothing names the pull request. Caprock sums cost per repository and per merged pull request from the session files on the machine.
Sources
- Claude Code docs — Monitoring (the quick start, administrator configuration, the variables table, cardinality control, standard and repository attributes, the metrics and events, security and privacy), read 30 October 2026 as the page's .md route
- Claude Code docs — Manage costs effectively (cloud providers, the list-price sentence, the options table), read 30 October 2026
- Claude Code docs — Settings (precedence, env in settings files, the telemetry variables project and local settings cannot set), read 30 October 2026
- Claude Code docs — Settings reference (env, variables Claude Code ignores in env, modelPricing), read 30 October 2026
- Claude Code docs — Environment variables (CLAUDE_CODE_ENABLE_TELEMETRY, the OTEL_* rows, DISABLE_TELEMETRY, startup-only reads), read 30 October 2026
- Claude Code docs — Deploy managed settings (the file paths per OS, turning Anthropic's telemetry off for an organization), read 30 October 2026
- Claude Code docs — Data usage (telemetry services, default behaviours by API provider), read 30 October 2026
- Claude Code docs — Track team usage with analytics (sends admins to OpenTelemetry for per-user token counts), read 30 October 2026
- Caprock architecture — ingest tails the transcript JSONL under ~/.claude/projects; hooks and tailing have no platform-specific code
- Caprock's dated price table, the list rates each turn is priced at
- Caprock — the team edition: aggregates by work unit, no field for content, the person dimension a switch
- Caprock's measured figures: the seven-day window hourly and sessions by who started them, 29 September to 28 October 2026, one developer's Mac; the charts on /teams/ read the same file (src/content/charts.ts)
Try it
The record of every coding agent you run, the sessions it did not start included. Free, open source; nothing leaves your machine.
Notarized by Apple. One file for Apple silicon and Intel, macOS 13 or later.
Or run it yourself:
Paste in Terminal: it installs Caprock and opens it.Or with Homebrew: brew install --cask dspv/tap/caprock-app