Skip to content

OpenTelemetry and Analytics for Claude Code, Codex and Cursor

Coding-agent telemetry comes in three layers: OpenTelemetry export to a collector you run, vendor analytics dashboards for adoption and pull request attribution, and per-commit provenance from Entire CLI. The claude.ai dashboard shows no per-user cost; that comes from OpenTelemetry, the spend report or, on Enterprise, the Analytics API. Cursor had no verified OpenTelemetry export on 2026-09-26.

This page is for the developer who wants to see what their agent sessions cost and do, and the tech lead who has to answer “is the agent rollout working?” at the next planning meeting. You have 12 seats, an invoice, and a dashboard that says 70% of people were active last week. Nobody can tell you which models the money went to, which merged pull requests the agents wrote, or whether those changes survived.

The canonical page for production telemetry pipelines, audit retention and join keys is observing the agents. The observability and quality overview places this page among the cost, review, security and eval tools. This page is the tool shelf: what each product emits, a local stack you start with one command, and the monthly adoption review built on it.

  • A working local stack: Claude Code and Codex exporting OpenTelemetry into Grafana on your laptop, verified with a single query.
  • PromQL for the six Claude Code panels a tech lead asks for: cost by model, tokens by type, active users, sessions, edit accept rate, and commits and pull requests.
  • A clear map of what the Claude Code analytics dashboard shows, what it hides (per-user cost), and when it goes dark (Zero Data Retention).
  • Entire CLI set up per tool, so any commit leads back to the prompts and session that produced it.
  • A monthly adoption review in four steps, and three copy-paste prompts that automate it.

Start by knowing which layer answers which question. Telemetry answers “what did the sessions do and cost?”; analytics answers “who uses it and how much merged code came from it?”; provenance answers “why was this commit written this way?”.

LayerClaude Code 2.1.283Codex CLI 0.157.1Cursor
OpenTelemetry exportMetrics and log events; traces in beta (CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1)Logs, traces and metrics from [otel] in config.tomlNone verified on 2026-09-26
Cost signalclaude_code.cost.usage (USD) with model, effort, query_sourcecodex.turn.cost_microusdNot verified
Delivery signalclaude_code.commit.count, claude_code.pull_request.count, claude_code.lines_of_code.countNo commit or pull request metric in codex-rs/otel at rust-v0.157.1Not verified
Vendor dashboardclaude.ai/analytics/claude-code (Team, Enterprise); platform.claude.com/claude-code (Console)Enterprise analytics dashboard and Analytics API (secondary: OpenAI help pages seen only in search extracts)Team/Enterprise analytics dashboard and Analytics API; AI Code Tracking API (Enterprise only) maps AI-generated lines to commits (secondary: cursor.com docs seen only in search extracts; endpoints unverified)
Per-session view on your machine/usage (/cost and /stats are aliases); /insights writes an HTML report on recent sessionscodex exec --json events per runNot verified
Commit provenanceEntire CLI (entire enable --agent claude-code)Entire CLI (--agent codex)Entire CLI (--agent cursor)

Sources: Claude Code monitoring and analytics docs; Codex source (codex-rs/config/src/types.rs and codex-rs/otel/src/metrics/names.rs at rust-v0.157.1); the entireio/cli README; all read 2026-09-26.

The shared OpenTelemetry vocabulary for agents (invoke_agent, execute_tool) lives in open-telemetry/semantic-conventions-genai and was still Status: Development on 2026-09-26, so each tool uses its own names. Build dashboards per tool now and expect renames later.

What does the Claude Code analytics dashboard show, and what does it hide?

Section titled “What does the Claude Code analytics dashboard show, and what does it hide?”

The Team and Enterprise dashboard at claude.ai/analytics/claude-code is the fastest adoption view, and it has four limits that change how you use it:

  • No per-user cost. It shows lines accepted, suggestion accept rate, daily active users, sessions, contribution metrics, and a top-10 leaderboard with a CSV export of all users. Per-user tokens and cost come from OpenTelemetry or from the spend report in your organization’s analytics settings.
  • Contribution metrics need GitHub and are a public beta. An Owner enables analytics and the GitHub analytics toggle at claude.ai/admin-settings/claude-code, and a GitHub admin installs the app at github.com/apps/claude. Data typically appears within 24 hours. Only users in your claude.ai organization count; Console API usage does not.
  • Zero Data Retention turns contribution metrics off. A ZDR organization sees usage metrics only, so pull request attribution has to come from your own labels or Entire trailers.
  • Attribution is deliberately conservative. A merged pull request counts when Claude Code sessions from 21 days before to 2 days after the merge match its added lines; code rewritten by more than 20% is not attributed, and lock files, build output and snapshots are excluded. Credited pull requests get the GitHub label claude-code-assisted.

That label is the cheapest attribution query you have. In GitHub search, is:pr is:merged label:claude-code-assisted lists every merged pull request the engine credited, without API access. On Enterprise, the Claude Enterprise Analytics API returns per-user engagement, usage and cost reports with a key that has the read:analytics scope; the Team plan does not get the API. Console customers use the Claude Code Analytics API with an Admin API key, and the Console notes that its spend figures are estimates, not billing.

Send Claude Code and Codex telemetry to a local Grafana stack

Section titled “Send Claude Code and Codex telemetry to a local Grafana stack”

This is the full example: one container, two agents, one query that proves data arrives. It runs on your laptop and costs nothing but disk. The grafana/otel-lgtm image bundles an OpenTelemetry Collector, Prometheus, Loki, Tempo, Pyroscope and Grafana; Grafana describes it as intended for development, demo and testing, not production.

  1. Start the stack. In a terminal:

    Terminal window
    docker run --rm --name lgtm \
    -p 3000:3000 -p 4317:4317 -p 4318:4318 -p 9090:9090 \
    grafana/otel-lgtm

    Port 3000 is Grafana (log in as admin / admin), 4317 is OTLP over gRPC, 4318 is OTLP over HTTP, and 9090 is Prometheus, which the prompts below query directly.

  2. Point each agent at the collector. The settings differ per tool.

    Export the variables in the shell that starts claude, or put the same keys under env in ~/.claude/settings.json. Claude Code ignores exporter variables in a repository’s .claude/settings.json and .claude/settings.local.json, so a repository cannot turn telemetry on or redirect it.

    Terminal window
    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_METRICS_TEMPORALITY_PREFERENCE=cumulative
    export OTEL_METRIC_EXPORT_INTERVAL=10000
    export OTEL_METRICS_INCLUDE_REPOSITORY=true
    claude

    Claude Code has no default OTLP protocol, so OTEL_EXPORTER_OTLP_PROTOCOL is required. Temporality defaults to delta; the docs say to switch to cumulative when the backend needs it, and a Prometheus-backed stack stores cumulative counters. The 10-second interval is for testing; the default is 60 seconds. OTEL_METRICS_INCLUDE_REPOSITORY=true (v2.1.269 and later) adds vcs.repository.name and related attributes, so you can filter by repository.

    Prompt text, tool input and responses stay redacted unless you set OTEL_LOG_USER_PROMPTS, OTEL_LOG_TOOL_DETAILS or OTEL_LOG_ASSISTANT_RESPONSES. Leave them off here.

  3. Prove data arrives. Run one short session in each agent, then open Grafana at http://localhost:3000, go to Explore, pick the Prometheus data source, and run:

    {__name__=~"claude_code_session_count.*|codex_thread_started.*"}

    You should see one series per session start within about 10 seconds for Claude Code. Dots in OpenTelemetry names become underscores in Prometheus, and Prometheus can append a unit or _total suffix, which is why every query here matches on a name prefix. For events, pick the Loki data source and search for user_prompt. If nothing arrives, run claude --debug-file /tmp/claude-otel.log and search that file for [3P telemetry]; lines tagged [Anthropic telemetry] are Anthropic’s own operational telemetry and do not indicate a problem.

  4. Build the six Claude Code panels. Create a dashboard with one panel per query, each over a 7-day range:

    # Cost by model (USD, client-side estimate)
    sum by (model) (increase({__name__=~"claude_code_cost_usage.*"}[7d]))
    # Tokens by type: input, output, cacheRead, cacheCreation
    sum by (type) (increase({__name__=~"claude_code_token_usage.*"}[7d]))
    # Active users (count only; never chart per person)
    count(count by (user_email) (increase({__name__=~"claude_code_session_count.*"}[7d]) > 0))
    # Sessions by start type: fresh, resume, continue, agents_view
    sum by (start_type) (increase({__name__=~"claude_code_session_count.*"}[7d]))
    # Edit accept rate: Edit, Write, NotebookEdit decisions
    sum(increase({__name__=~"claude_code_code_edit_tool_decision.*", decision="accept"}[7d]))
    / sum(increase({__name__=~"claude_code_code_edit_tool_decision.*"}[7d]))
    # Commits and pull requests the agent created
    sum(increase({__name__=~"claude_code_commit_count.*|claude_code_pull_request_count.*"}[7d]))

    The accept-rate panel counts every decision, including edits that settings, the permission mode or a hook accepted without a person (source="config" or source="hook"), so in permissive modes it drifts toward 100%. For a human accept rate, add source=~"user_.*" to both the numerator and the denominator.

    With per-session series, increase() misses each series’ first sample, so short sessions undercount. For totals you reconcile against the invoice, use sum by (model) (max_over_time({__name__=~"claude_code_cost_usage.*"}[7d])), or set OTEL_METRICS_INCLUDE_SESSION_ID=false for dashboard metrics.

    If a label such as user_email is missing, open the metric in Explore and use the label name your stack shows. Add Codex panels the same way once codex_ series appear.

  5. Move from laptop to team. When the panels answer real questions, replace the container with a production collector and push the Claude Code variables through managed settings, which override developer-set exporter variables. For a rotating collector token, point otelHeadersHelper in settings at a script that prints the headers as JSON; Claude Code reruns it every 29 minutes by default. The production pipeline (pseudonymized analytics stream, identified audit stream, retention) is on the agent observability page.

Two open reference stacks save you the dashboard work if you want more than six panels. As of 2026-09-26 (GitHub stars, read through the GitHub API for the site’s research catalogue): ColeMurray/claude-code-otel (506 stars) is a Docker Compose stack of collector, Prometheus, Loki and Grafana with prebuilt cost, tool, user and session dashboards (make up); anthropics/claude-code-monitoring-guide (370 stars) is Anthropic’s ROI guide with a docker-compose.yml, otel-collector-config.yaml, Grafana dashboards and a report-generation prompt. Neither covers Codex.

Trace a commit back to its session with Entire CLI

Section titled “Trace a commit back to its session with Entire CLI”

Metrics tell you that 40 commits came from agent sessions last week. They do not tell you why a specific line in billing/retry.ts looks the way it does. Entire CLI (Entire Inc., MIT, entireio/cli) fills that gap: it installs git hooks plus per-agent hooks, captures prompts, transcript, tool calls, files touched and token usage while the agent works, and on commit condenses them into a checkpoint linked by an Entire-Checkpoint: <id> commit trailer. Entire never creates commits on your branch.

Popularity as of 2026-09-26: 5.1k GitHub stars; latest stable v0.11.3, published 2026-09-25 (GitHub API and releases page). It is a Go binary; the npm package entire is an unrelated project.

Terminal window
brew install --cask entireio/tap/entire
cd your-project
entire enable --agent claude-code # hooks land in .claude/settings.json
entire status

Add a second agent later with entire agent add codex. Team settings go in .entire/settings.json; personal overrides go in the gitignored .entire/settings.local.json. Other install routes in the README are an install script, Scoop on Windows and go install.

Reviewing an agent-written pull request then looks like this:

Terminal window
git log -1 --format=%B # message ends with: Entire-Checkpoint: <id>
entire checkpoint explain <CHECKPOINT_ID> # prompts, transcript, files touched, tokens
entire search "rate limiter retry" # search across checkpoints, commits and sessions

CHECKPOINT_ID is the value after Entire-Checkpoint: in the commit message. Checkpoints are stored as git refs under refs/entire/checkpoints/ and pushed with your normal git push; the older single entire/checkpoints/v1 branch is the legacy backend.

Run the monthly adoption review: usage, attribution, outcomes

Section titled “Run the monthly adoption review: usage, attribution, outcomes”

Telemetry pays off only when it feeds a decision. The review below runs monthly and is owned by the tech lead. It follows the utilization, impact and cost split that DX’s AI Measurement Framework uses (secondary: DX research page seen in a search extract), with the metric definitions from the site’s metrics frameworks page.

  1. Usage: who uses which agent, on which models, at what cost. Pull active users, sessions and cost by model from the Grafana panels (Claude Code and Codex) and from the vendor dashboards (all three tools). Compare active users with paid seats. Report cost by model and by repository, never by person.

  2. Attribution: which merged changes involved an agent. Combine three sources, strongest first: your own agent-assisted pull request label or template checkbox, the claude-code-assisted label from the Claude Code dashboard, and Entire-Checkpoint trailers in merged commits. A pull request with any of them counts as agent-assisted. The vendor label alone undercounts, because it ignores Codex and Cursor and is deliberately conservative.

  3. Outcomes: did those changes survive. For the agent-assisted cohort and the rest, compute accepted change rate, 14-day follow-up fix rate and review time, as defined on the metrics page. Divide the month’s agent spend (seats plus usage) by accepted agent-assisted changes to get cost per accepted change.

  4. Decide and record. Pick at most two changes for next month (a model switch, a context file fix, a training session for a repository with low adoption) and write down which number should move. The tech lead signs off the review; the next review checks whether the number moved.

How do you know the telemetry numbers are right?

Section titled “How do you know the telemetry numbers are right?”

A dashboard nobody has checked is an opinion. Verify it once when you set it up, then monthly, without reading any agent diff:

  • Reconcile cost with the invoice. claude_code.cost.usage and codex.turn.cost_microusd are computed on the client, and the Console states that its own spend figures are estimates. Compare the month’s telemetry total with the invoice; the invoice is the number you report, and telemetry is the breakdown.
  • Smoke-test every machine image. One session per laptop image and CI image, followed by the step 3 query. A CI image without the variables is a silent hole in every total.
  • Spot-check attribution. Take five merged pull requests: confirm each label or Entire trailer against the session that produced it. Record the error rate on the review page.
  • Alert on silence. A Grafana alert on “no claude_code_session_count data for 24 hours on a working day” catches a broken exporter before the monthly review does.
  • Keep identity out of analytics. The review counts users; it never ranks them. The career ladders page explains why per-person token or PR counts turn into targets people game.

What breaks when you collect agent telemetry, and how to recover

Section titled “What breaks when you collect agent telemetry, and how to recover”

Claude Code runs but no metrics arrive. The usual cause is a missing OTEL_EXPORTER_OTLP_PROTOCOL or variables placed in project settings. Recovery: set the protocol, move the variables to the shell, user settings or managed settings, and check the debug file for [3P telemetry] errors.

Metrics arrive but the panels stay empty or jump. Delta temporality against a cumulative backend. Recovery: set OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=cumulative and restart the session.

Codex telemetry is missing. Either a key name is misspelled (Codex ignores it silently) or [otel] sits in another CODEX_HOME than the one the session reads. Recovery: confirm CODEX_HOME, then diff your keys against exporter, trace_exporter and metrics_exporter. A reported issue (openai/codex#12913, status unverified on 0.157.1) says codex exec emits no OpenTelemetry metrics, so confirm headless runs separately before you build panels on them.

Prometheus storage grows fast. session.id is on every Claude Code metric by default, so each session is a new series. Recovery: in a large team, set OTEL_METRICS_INCLUDE_SESSION_ID=false and keep session IDs on log events, where cardinality is cheap.

The adoption review shows Claude Code winning and Codex invisible. The vendor label only credits Claude Code, and Codex 0.157.1 emits no commit metric. Recovery: attribute through your own agent-assisted label and Entire trailers, which cover all three tools.

A secret appears in the log store. Someone turned on OTEL_LOG_TOOL_DETAILS or OTEL_LOG_USER_PROMPTS. Recovery: rotate the secret, purge the records, and route content only to the audit pipeline described on the agent observability page.

PR attribution disappears after a contract change. Zero Data Retention switches contribution metrics off. Recovery: keep your own label and Entire trailers as the primary attribution, so the review does not depend on one vendor feature.

Frequently asked questions

Does the Claude Code analytics dashboard show cost per user?

No. The Team and Enterprise dashboard shows usage, contribution metrics and a leaderboard. For per-user tokens and cost, export OpenTelemetry to your own collector, download the spend report from the organization's analytics settings or, on Enterprise, call the Analytics API.

How do I turn on OpenTelemetry in Claude Code?

Set CLAUDE_CODE_ENABLE_TELEMETRY=1 plus OTEL_METRICS_EXPORTER and OTEL_LOGS_EXPORTER, and set OTEL_EXPORTER_OTLP_PROTOCOL because Claude Code has no default protocol. Variables in a repository's .claude/settings.json are ignored; use your shell, user settings or managed settings.

How do I export Codex telemetry?

Add an [otel] table to ~/.codex/config.toml with exporter, trace_exporter and metrics_exporter set to otlp-grpc or otlp-http. Set metrics_exporter explicitly, because in Codex CLI 0.157.1 it defaults to statsig.

Are PR attribution metrics available under zero data retention?

No. Organizations with Zero Data Retention see usage metrics only on the Claude Code dashboard; contribution metrics, including PR attribution, are unavailable. Use your own pull request labels or Entire CLI commit trailers instead.