Claude Code OpenTelemetry: the variables, the metrics, and what the stream never carries

Dmitriy Solodukha · checked against Caprock v0.166.0

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_TELEMETRY is required; without it the other variables do nothing.
  • The exporters. OTEL_METRICS_EXPORTER takes console, otlp, prometheus, none; OTEL_LOGS_EXPORTER takes console, otlp, none. Both are optional: configure the signal you want, and none turns 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 each otlp exporter you enable". OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT and the _PROTOCOL pair override the generic variable for one signal; per-signal headers merge with the generic ones.
  • The intervals. OTEL_METRIC_EXPORT_INTERVAL defaults to 60,000 ms and OTEL_LOGS_EXPORT_INTERVAL to 5,000 ms. Lower them to debug, put them back for production.
  • The check. claude_code.session.count arrives when a session starts; for a logs-only setup, send a prompt and look for claude_code.user_prompt. If nothing arrives, run claude --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.json and .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.json can; a repository can only set an exporter to none.
  • 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.

The metrics on the monitoring page, read 30 October 2026; every name begins claude_code.. The unit is the OpenTelemetry unit string, and count metrics carry none.
MetricCountsBeyond the standard attributes
session.countCount of CLI sessions startedstart_type: fresh, resume, continue or agents_view
lines_of_code.countCount of lines of code modifiedtype: added or removed; model
pull_request.countNumber of pull requests createdthe standard attributes only
commit.countNumber of git commits createdthe standard attributes only
cost.usageCost of the Claude Code session, in USDmodel, query_source, speed, effort, and the agent, skill, plugin and MCP names
token.usageNumber of tokens used, in tokenstype: input, output, cacheRead or cacheCreation; then as the cost counter
code_edit_tool.decisionCount of code editing tool permission decisionstool_name, decision, source, language
active_time.totalTotal active time, in stype: user or cli
Cost and tokens increment after each API request. The token 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 unless OTEL_LOG_USER_PROMPTS=1; command_name when the prompt was a / command.
  • claude_code.tool_result — tool_name, success, duration_ms, error_type, the input and result sizes in bytes, the permission decision_source; with OTEL_LOG_TOOL_DETAILS=1, tool_parameters with the Bash command and tool_input with 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-mode classifier_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.

The standard attributes that name a person or a session, with what controls each, from the monitoring page read 30 October 2026.
AttributeCarries, and what controls it
user.emailthe sign-in email; Always included when available
user.ida random id kept in ~/.claude.json; Always included
user.account_uuidthe account UUID; OTEL_METRICS_INCLUDE_ACCOUNT_UUID, default true
user.account_idthe account id in the admin APIs' format; OTEL_METRICS_INCLUDE_ACCOUNT_UUID, default true
organization.idthe organization UUID; Always included when available
session.idthe session, replaced by /clear; OTEL_METRICS_INCLUDE_SESSION_ID, default true
terminal.typeiTerm.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.email is "Always included when available". Anthropic's page: "When authenticated via OAuth, user.email is 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=false drops user.account_uuid and user.account_id; OTEL_METRICS_INCLUDE_SESSION_ID=false drops session.id. "Lower cardinality generally means better performance and lower storage costs but less granular data for analysis."
  • user.id stays, 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=42 puts those keys on every datapoint (OTEL_METRICS_INCLUDE_RESOURCE_ATTRIBUTES, default true). On a Claude apps gateway sign-in the stream also carries user.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."

What the repository attributes carry, from the monitoring page read 30 October 2026.
AttributeValue
vcs.repository.url.fullthe browser URL, without .git
vcs.owner.namethe owner or group path; omitted for a single-segment path
vcs.repository.namethe bare repository name
vcs.provider.namegithub, 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

Try it

The record of every coding agent you run, the sessions it did not start included. Free, open source; nothing leaves your machine.

Download for Mac

Notarized by Apple. One file for Apple silicon and Intel, macOS 13 or later.

Or run it yourself:

curl -fsSL https://caprock.dev/mac.sh | sh

Paste in Terminal: it installs Caprock and opens it.Or with Homebrew: brew install --cask dspv/tap/caprock-app