What you will be able to do
- Explain what telemetry content is redacted by default and which OTEL_LOG_* variable reveals each kind
- Tag telemetry by service and tenant, and send audit events to a SIEM
- Query the Usage & Cost Admin API for token and cost trends at the right granularity
- Say what the Claude Code analytics dashboard adds on top of telemetry
1.What telemetry records by default, and the gates that reveal more
By default, telemetry records what happened, not what was said. Raw file contents and code snippets are not included in metrics or events. Prompts and responses are recorded only as lengths. A set of separate OTEL_LOG_* variables reveals more, and each one opens a specific kind of content. Telemetry is sent only to the endpoint you configure, never to Anthropic, but anything you reveal will be stored in your backend. The guide therefore advises configuring that backend to filter or redact sensitive attributes.
| Variable | Adds |
|---|---|
| OTEL_LOG_USER_PROMPTS=1 | Prompt text on claude_code.user_prompt events and on the claude_code.interaction span |
| OTEL_LOG_ASSISTANT_RESPONSES=1 | Assistant response text on assistant_response events |
| OTEL_LOG_TOOL_DETAILS=1 | Tool input arguments such as file paths, shell commands, and search patterns |
| OTEL_LOG_TOOL_CONTENT=1 | A tool.output span event on claude_code.tool; requires tracing to be enabled |
| OTEL_LOG_RAW_API_BODIES | Full Messages API request and response JSON, with extended-thinking content redacted |
Two interactions between the gates catch people out. First, OTEL_LOG_ASSISTANT_RESPONSES falls back to OTEL_LOG_USER_PROMPTS when it is unset. Turning on prompts alone therefore turns on responses too, unless you explicitly set the response flag to 0. Second, raw API bodies contain the whole conversation history, so enabling them amounts to enabling every other content gate. Content-bearing attributes are truncated at a content limit of 60 KB by default, which CLAUDE_CODE_OTEL_CONTENT_MAX_LENGTH can change.
Checkpoint 1 of 5· Check yourself
A team sets OTEL_LOG_USER_PROMPTS=1 so they can debug prompt drift. They must not store model responses. What else do they need to do?
When OTEL_LOG_ASSISTANT_RESPONSES is unset, it inherits the value of OTEL_LOG_USER_PROMPTS. Responses stay redacted only if it is explicitly set to 0.
“When this variable is unset, OTEL_LOG_USER_PROMPTS is used as a fallback, so set OTEL_LOG_ASSISTANT_RESPONSES=0 if you want prompt content without response content”Source: code.claude.com
2.Tagging deployments and routing audit events
Telemetry from many agents is only useful if you can tell them apart. In the Agent SDK, the standard OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES variables label everything an agent emits. The guide's example uses them for service, version and deployment environment. A second example sets enduser.id and tenant.id per request, so that cost and latency can be broken down by customer.
options = ClaudeAgentOptions(
env={
# ... exporter configuration from the Enable telemetry export example ...
"OTEL_SERVICE_NAME": "support-triage-agent",
"OTEL_RESOURCE_ATTRIBUTES": "service.version=1.4.0,deployment.environment=production",
},
)Log events also serve as an audit trail. tool_decision records whether a tool call was allowed or denied, and by what. permission_mode_changed records escalations. hook_execution_complete shows policy hooks that blocked an action. auth and mcp_server_connection record logins and server failures. To record the actual commands run and files touched, OTEL_LOG_TOOL_DETAILS=1 must be set as well. The guide's SIEM example sends only the logs signal to a security collector.
Checkpoint 2 of 5· Fill the gap
This config sends audit logs to a SIEM and must record which Bash commands ran and which files were touched. Which variable fills the blank?
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_LOGS_EXPORTER": "otlp",
" ? ": "1",
"OTEL_EXPORTER_OTLP_LOGS_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT": "https://siem.example.com:4318/v1/logs",
"OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer your-siem-token"
}
}Commands run and files touched appear as tool_parameters and tool_input only when OTEL_LOG_TOOL_DETAILS=1. OTEL_LOG_TOOL_CONTENT adds tool output to trace spans, and this config only exports logs.
Source: code.claude.comSources1
3.Organisation-wide trends with the Usage & Cost Admin API
OpenTelemetry shows what one deployment is doing. The Usage & Cost Admin API shows the whole organisation's historical API usage, the same data as the Console's Usage and Cost pages. Its stated uses include tracking product performance, checking whether a change to the system improved it, setting up alerts, and tuning prompt caching for capacity. It requires an Admin API key. Claude Enterprise organisations use the Analytics API with an Analytics API key instead.
/v1/organizations/usage_report/messages reports token counts split into uncached input, cached input, cache creation and output. You can filter and group by API key, workspace, model, service tier, context window, data residency, or speed.
curl "https://api.anthropic.com/v1/organizations/usage_report/messages?\
starting_at=2025-01-01T00:00:00Z&\
ending_at=2025-01-08T00:00:00Z&\
group_by[]=model&\
bucket_width=1d" \
-H "anthropic-version: 2023-06-01" \
-H "x-api-key: $ANTHROPIC_ADMIN_KEY"| Endpoint | Bucket width | Default / maximum buckets | Use case |
|---|---|---|---|
| usage_report/messages | 1m | 60 / 1,440 | Real-time monitoring |
| usage_report/messages | 1h | 24 / 168 | Daily patterns |
| usage_report/messages | 1d | 7 / 31 | Weekly/monthly reports |
| cost_report | 1d only | n/a | Costs in USD, grouped by workspace or description |
/v1/organizations/cost_report returns costs in USD as decimal strings in cents. It covers token usage, web search and code execution, but only in daily buckets. For a sub-daily view, use the usage endpoint's token counts. Both endpoints return results in pages.
Checkpoint 3 of 5· Put it in order
Put the steps for paginating a large usage or cost report in order
- 1.Repeat until has_more is false
- 2.Make the initial request
- 3.Send the next request with the next_page value
- 4.Check whether has_more is true in the response
The documented loop: make the request, use next_page while has_more is true, and stop when it becomes false.
“If has_more is true, use the next_page value in your next request.”Source: platform.claude.com
Checkpoint 4 of 5· Exam question
During an active incident, an on-call engineer needs a near real-time view of organization-wide token consumption spikes, checking for anomalies roughly once a minute. Which Usage API configuration fits this monitoring need within the documented granularity limits?
Correct answer: A — Request bucket_width=1m, raise the limit above the 60-bucket default up to the 1440-bucket maximum as needed, and poll about once per minute
- A. Correct. Minute-level buckets are intended for real-time monitoring, the limit can be raised well past its default to capture a longer recent window, and roughly once-per-minute polling matches the documented sustained polling guidance.
- B. Incorrect. Daily buckets aggregate an entire day into one data point, which cannot reveal minute-level spikes during an active incident regardless of how many buckets are requested.
- C. Incorrect. Hourly buckets aggregate a full hour of usage into a single value; they do not refresh at 60-second intervals, and they are too coarse to spot a spike within a given hour.
- D. Incorrect. Polling far more frequently than the recommended once-per-minute cadence does not produce fresher underlying data, since usage figures typically finalize within about five minutes of request completion, and it needlessly increases API load.
Sources3
4.The Claude Code analytics dashboard
For Claude Code specifically, there is also an analytics dashboard that needs no backend. Teams and Enterprise plans use claude.ai/analytics/claude-code. API customers use platform.claude.com/claude-code. Both show adoption-level signals: daily active users and sessions, lines of code accepted, and suggestion accept rate. The Console version adds spend, which is daily API costs in dollars shown alongside user count, plus per-user spend for the month. The guide suggests watching for dips in usage, which may point to friction or problems. Telemetry and the Usage API are where you then look for the cause.
Checkpoint 5 of 5· Check yourself
Which view does the Console (API) Claude Code analytics dashboard offer that helps you link adoption to cost?
The Console dashboard's Spend view puts daily cost next to the number of active users. Span latency and raw bodies come from OpenTelemetry, not the dashboard.
“Spend: daily API costs in dollars alongside user count.”Source: code.claude.com
Sources4
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Enabling OTEL_LOG_USER_PROMPTS only exposes prompt text. Response text stays redacted unless you turn it on separately.Why is that wrong?
OTEL_LOG_ASSISTANT_RESPONSES falls back to OTEL_LOG_USER_PROMPTS when unset. Responses stay redacted only if it is explicitly set to 0.
Covered in What telemetry records by default, and the gates that reveal more
2.The cost_report endpoint can be bucketed hourly, like usage_report.Why is that wrong?
Cost reports are daily only. For minute or hour granularity, use the token counts from usage_report/messages.
Covered in Organisation-wide trends with the Usage & Cost Admin API
Practise it for real
Pull a week of token usage grouped by model and check whether prompt caching is taking effect
1.Export an Admin API key as ANTHROPIC_ADMIN_KEY and run the usage_report curl from this page with group_by[]=model and bucket_width=1d
Why: The Usage API needs an Admin API key and reports historical usage for the whole organisation
You should see: Daily buckets for the requested range, with token counts broken down by model
2.Compare the cached input and cache creation token counts with uncached input for each model
Why: The usage report separates these token types, which shows whether prompts are being served from the cache
You should see: Cached input should be non-zero for workloads that reuse prompt prefixes
3.If the response contains has_more: true, repeat the request with page set to the next_page value
Why: Both endpoints return large datasets in pages
You should see: The final page returns has_more: false
4.Run the cost_report request grouped by workspace_id and description for the same range
Why: Cost reports give USD figures to set beside the token counts
You should see: Daily cost buckets with costs as decimal strings in cents
Stuck? Get a nudge
If you need sub-daily resolution, change bucket_width on the usage endpoint. The cost endpoint accepts only 1d.
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.https://code.claude.com/docs/en/monitoring-usageOfficial docs
“Raw file contents and code snippets are not included in metrics or events.”
↩︎ What telemetry records by default, and the gates that reveal more“sent only to the OTel endpoint you configure, never to Anthropic”
↩︎ What telemetry records by default, and the gates that reveal more“Commands run and files touched | tool_result (executed) or tool_decision (rejected) with OTEL_LOG_TOOL_DETAILS=1”
↩︎ Tagging deployments and routing audit events“When this variable is unset, OTEL_LOG_USER_PROMPTS is used as a fallback”
↩︎ Exam trap 1“User prompt content is not collected by default. Only prompt length is recorded.”
↩︎ Prediction“When this variable is unset, OTEL_LOG_USER_PROMPTS is used as a fallback, so set OTEL_LOG_ASSISTANT_RESPONSES=0 if you want prompt content without response content”
↩︎ Checkpoint - 2.
“Enabling this implies consent to everything the three variables above would reveal”
↩︎ What telemetry records by default, and the gates that reveal more - 3.
“Monitor product performance while measuring if changes to the system have improved it, or set up alerting”
↩︎ Organisation-wide trends with the Usage & Cost Admin API“Measure uncached input, cached input, cache creation, and output tokens”
↩︎ Organisation-wide trends with the Usage & Cost Admin API“Time buckets: Daily granularity only (1d)”
↩︎ Exam trap 2“If has_more is true, use the next_page value in your next request.”
↩︎ Checkpoint - 4.https://code.claude.com/docs/en/analyticsOfficial docs
“Dips in usage that may indicate friction or issues”
↩︎ The Claude Code analytics dashboard“Spend: daily API costs in dollars alongside user count.”
↩︎ Checkpoint