Claude Code can export OpenTelemetry (OTel) data to track usage, costs, and tool activity. This is opt-in and requires explicit configuration.
Quick Start
1. Enable Telemetry
export CLAUDE_CODE_ENABLE_TELEMETRY=1
Or in .claude/settings.json:
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1"
}
}
2. Choose Exporters
# Export metrics
export OTEL_METRICS_EXPORTER=otlp
# Export events/logs
export OTEL_LOGS_EXPORTER=otlp
# Or console for debugging
export OTEL_METRICS_EXPORTER=console
3. Configure Endpoint
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
4. Optional: Authentication
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your-token"
5. Start Claude Code
claude
Metrics and events will now be exported to your collector.
Exporter Options
OTLP (OpenTelemetry Protocol)
Standard protocol — works with most backends.
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
Backends:
- OpenTelemetry Collector
- Datadog
- New Relic
- Honeycomb
- Jaeger
Prometheus
For metrics directly into Prometheus:
export OTEL_METRICS_EXPORTER=prometheus
Starts a Prometheus endpoint on port 8888.
Console
For debugging — metrics are printed to console:
export OTEL_METRICS_EXPORTER=console
export OTEL_METRIC_EXPORT_INTERVAL=10000 # Every 10 seconds
Configuration
Environment Variables
| Variable | Description | Example |
|---|---|---|
CLAUDE_CODE_ENABLE_TELEMETRY |
Enable telemetry (MUST be set) | 1 |
OTEL_METRICS_EXPORTER |
Metrics exporter | otlp, prometheus, console |
OTEL_LOGS_EXPORTER |
Logs/events exporter | otlp, console |
OTEL_EXPORTER_OTLP_ENDPOINT |
OTLP collector endpoint | http://localhost:4317 |
OTEL_EXPORTER_OTLP_PROTOCOL |
OTLP protocol | grpc, http/json, http/protobuf |
OTEL_EXPORTER_OTLP_HEADERS |
Auth headers | Authorization=Bearer token |
OTEL_METRIC_EXPORT_INTERVAL |
Export interval in ms | 60000 (default) |
OTEL_LOGS_EXPORT_INTERVAL |
Logs export interval | 5000 (default) |
Cardinality Control
Reduce metrics cardinality (less storage):
export OTEL_METRICS_INCLUDE_SESSION_ID=false
export OTEL_METRICS_INCLUDE_ACCOUNT_UUID=false
export OTEL_METRICS_INCLUDE_VERSION=false
Available Metrics
Sessions
claude_code.session.count
Counter: New sessions started.
Attributes:
session.iduser.emailorganization.id
Code Changes
claude_code.lines_of_code.count
Counter: Lines added/removed.
Attributes:
type:"added"or"removed"
Commits
claude_code.commit.count
Counter: Git commits created.
Pull Requests
claude_code.pull_request.count
Counter: PRs created.
Token Usage
claude_code.token.usage
Counter: Tokens used.
Attributes:
type:"input","output","cacheRead","cacheCreation"model: Model used
Cost
claude_code.cost.usage
Counter: Estimated costs in USD.
Attributes:
model: Model name
Tool Decisions
claude_code.code_edit_tool.decision
Counter: Code-edit approvals (accept/reject).
Attributes:
tool_name:"Edit","Write","NotebookEdit"decision:"accept"or"reject"language: Programming language
Active Time
claude_code.active_time.total
Counter: Active time in seconds (without idle).
Attributes:
type:"user"(keyboard) or"cli"(tool execution)
Available Events
User Prompt Event
When user enters a prompt.
Field: claude_code.user_prompt
Data:
prompt_lengthprompt(optional, enable withOTEL_LOG_USER_PROMPTS=1)
Tool Result Event
When a tool execution completes.
Field: claude_code.tool_result
Data:
tool_namesuccess: true/falseduration_mserror(if failed)
API Request Event
For each Claude API request.
Field: claude_code.api_request
Data:
modelcost_usdduration_msinput_tokensoutput_tokenscache_read_tokenscache_creation_tokens
API Error Event
When API request fails.
Field: claude_code.api_error
Data:
modelerrorstatus_codeattempt(retry number)
Dynamic Headers (Enterprise)
For organizations with dynamic authentication (token refresh):
{
"otelHeadersHelper": "/bin/generate_headers.sh"
}
Script must return JSON headers:
#!/bin/bash
echo "{\"Authorization\": \"Bearer $(get-token.sh)\"}"
Refreshed every 29 minutes. Interval configurable:
export CLAUDE_CODE_OTEL_HEADERS_HELPER_DEBOUNCE_MS=900000
Dashboards & Analysis
With Prometheus/Grafana
- Export metrics to Prometheus
- Create Grafana dashboard
- Query metrics:
rate(claude_code_token_usage_total{type="input"}[5m])
With Datadog
Connect Datadog OTel receiver:
export OTEL_EXPORTER_OTLP_ENDPOINT=http://datadog-agent:4317
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer $DD_API_KEY"
Metrics appear automatically in Datadog.
With Honeycomb
Use Honeycomb as OTel receiver:
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io
export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=$HC_API_KEY"
Team Multi-Tenancy
For organizations with multiple teams:
export OTEL_RESOURCE_ATTRIBUTES="department=engineering,team.id=platform,cost_center=eng-123"
All metrics are tagged with these attributes.
Formatting rules:
- Comma-separated key=value pairs
- No spaces in values
- Percent-encode special characters
# WRONG
export OTEL_RESOURCE_ATTRIBUTES="team=My Team"
# CORRECT
export OTEL_RESOURCE_ATTRIBUTES="team=my_team"
ROI Measurement
Base Metrics
| Metric | Description | Formula |
|---|---|---|
| LOC/Session | Code per session | total_lines_added / session_count |
| Cost/LOC | Cost per line | total_cost / total_lines_added |
| Time Saved | Estimated time | commits_count * avg_commit_time |
| Commits/Day | Velocity | commits_count / days |
Calculate ROI
ROI % = ((Time_Saved * Hourly_Rate) - Total_Cost) / Total_Cost * 100
Example:
- Time saved: 40 hours (400 commits × 6 min each)
- Hourly rate: $100
- Total cost: $500 (tokens)
ROI = ((40 × 100) - 500) / 500 × 100 = 7,900%
Cost Optimization
# Reduce export interval if unnecessary overhead
export OTEL_METRIC_EXPORT_INTERVAL=120000 # 2 minutes instead of 60s
# Disable session ID if cardinality is a problem
export OTEL_METRICS_INCLUDE_SESSION_ID=false
# Reduce event logging
export OTEL_LOG_USER_PROMPTS=0
export OTEL_LOG_TOOL_DETAILS=0
Security & Privacy
What Gets Collected
ALWAYS:
- Session ID
- User email (if OAuth)
- Organization ID
- Token counts
- Cost
- Tool names
ONLY if enabled:
- User prompt content (
OTEL_LOG_USER_PROMPTS=1) - MCP/skill names (
OTEL_LOG_TOOL_DETAILS=1)
What Does NOT Get Collected
- File contents
- Raw code
- Secrets/API keys
- Passwords
Redaction & Filtering
Your backend can filter telemetry:
# Only public metrics
rate(claude_code_cost_usage_total[5m])
# Exclude sensitive orgs
rate(claude_code_token_usage_total{organization_id!="private"}[5m])
Troubleshooting
Metrics Not Arriving
-
Check if enabled:
echo $CLAUDE_CODE_ENABLE_TELEMETRY -
Check if endpoint reachable:
curl http://localhost:4317/healthz -
Check if exporter configured:
echo $OTEL_METRICS_EXPORTER
Too Many Metrics (Cardinality Issue)
Problem: claude_code.session.count with every session ID creates 10000+ time series.
Solutions:
# Disable session ID
export OTEL_METRICS_INCLUDE_SESSION_ID=false
# Or use organization ID aggregation
export OTEL_RESOURCE_ATTRIBUTES="organization.id=org-1"
Authentication Failed
# Check if token valid
echo $OTEL_EXPORTER_OTLP_HEADERS
# Test with curl
curl -H "$OTEL_EXPORTER_OTLP_HEADERS" \
http://your-collector:4317/metrics
Further Resources
Last updated: 2026-03-21 | Claude Code Monitoring & Telemetry Reference
