Monitor every Claude Code session with OpenTelemetry and Grafana Cloud — see exactly what each session costs, how many tokens it burns, and where your money goes.
Claude Code is fantastic, but it's a black box when it comes to cost. You finish a session and wonder: How much did that just cost me? Was it the cache reads that added up, or the output tokens? How does today compare to yesterday?
The built-in /cost command gives you a snapshot of the current session, but there's no way to see historical data, compare sessions, or track spending trends over time.
Claude Code has built-in OpenTelemetry (OTEL) support. It can export metrics and events to any OTEL-compatible backend. This repo shows you how to wire it up to Grafana Cloud's free tier — which gives you a proper dashboard with cost breakdowns, token usage, and session tracking, at zero cost.
The setup takes about 5 minutes. No Docker, no collectors, no infrastructure. Just a config change and a free Grafana Cloud account.
The dashboard gives you:
| Panel | What it shows |
|---|---|
| Total Cost | Aggregate USD spend across all sessions |
| Total Tokens | Combined token count (input + output + cache) |
| Sessions | Number of distinct sessions tracked |
| Total Active Time | How long you've been actively using Claude Code |
| Sessions Table | Per-session breakdown: cost, active time, input/output tokens, cache read/write |
| Cost Over Time | Stacked bar chart of spend by model (Opus, Sonnet, Haiku) |
| Tokens Over Time | Stacked bar chart of token usage by type |
| Cost by Model | Pie chart showing which models eat your budget |
| Cost by Session (Top 10) | Horizontal bar chart of your most expensive sessions |
Go to grafana.com and sign up. The free tier includes:
- 50 GB of traces/logs per month
- 10,000 metrics series
- 14-day retention
- 3 users
- No credit card required
This is more than enough for personal Claude Code monitoring.
In Grafana Cloud:
- Go to your stack's Connections > Add new connection
- Search for OpenTelemetry (OTLP)
- Click Configure
- Note your OTLP endpoint (e.g.,
https://otlp-gateway-prod-us-east-0.grafana.net/otlp) - Generate an API token — make sure it has metrics:write and logs:write scopes
- Note the Instance ID and API key
- Create your Base64 credentials:
echo -n "INSTANCE_ID:API_KEY" | base64
Add the following to your ~/.claude/settings.json (merge into the existing "env" block if you have one):
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://otlp-gateway-prod-<REGION>.grafana.net/otlp",
"OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Basic <BASE64_CREDENTIALS>",
"OTEL_LOG_USER_PROMPTS": "1",
"OTEL_LOG_TOOL_DETAILS": "1",
"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE": "cumulative"
}
}Replace <REGION> with your Grafana Cloud region (e.g., us-east-0, eu-west-0, au-southeast-1) and <BASE64_CREDENTIALS> with the Base64 string from step 2.
Important: The
cumulativetemporality setting is critical. Without it, Grafana Cloud silently rejects Claude Code's metrics (they default to delta temporality, which Grafana's Mimir backend doesn't accept for counters). This is the most common reason metrics don't show up.
Option A: Via the Grafana UI
- In Grafana Cloud, go to Dashboards > New > Import
- Upload the
grafana-dashboard.jsonfile from this repo - Select your Prometheus datasource
- Click Import
Option B: Via the API
# Create a service account with Admin role in Grafana Cloud
# Administration > Service Accounts > Add > Role: Admin > Generate token
curl -X POST "https://YOUR_STACK.grafana.net/api/dashboards/db" \
-H "Authorization: Bearer YOUR_SERVICE_ACCOUNT_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"dashboard\": $(cat grafana-dashboard.json), \"overwrite\": true, \"folderUid\": \"\"}"Every new Claude Code session will now export telemetry to Grafana Cloud. Metrics flush every 60 seconds and log events every 5 seconds.
echo "hello" | claude --print # Quick testWait about 60 seconds, then check your dashboard.
You don't need to be a Grafana expert to use this dashboard. Here's a quick primer on what's happening under the hood.
When you enable telemetry, Claude Code uses the OpenTelemetry standard to export two types of data:
- Metrics — Numerical counters that get aggregated over time. These power the stat panels and time series charts. Metrics are stored in Prometheus (Grafana calls their hosted version "Mimir").
- Log events — Individual records for each API call, tool use, and user prompt. These are stored in Loki (Grafana's log storage).
Claude Code exports these metrics automatically:
| Metric | Labels | Description |
|---|---|---|
claude_code_cost_usage_USD_total |
model, session_id |
Cost in USD |
claude_code_token_usage_tokens_total |
type, model, session_id |
Token count by type (input, output, cacheRead, cacheCreation) |
claude_code_session_count_total |
session_id |
Session counter |
claude_code_active_time_seconds_total |
type, session_id |
Active time (cli vs user) |
claude_code_lines_of_code_count_total |
type, session_id |
Lines added/removed |
claude_code_commit_count_total |
session_id |
Git commits created |
claude_code_pull_request_count_total |
session_id |
PRs created |
| Event | Key fields | Description |
|---|---|---|
claude_code.api_request |
model, cost_usd, duration_ms, tokens | Every API call to Claude |
claude_code.user_prompt |
prompt_length, prompt (if enabled) | Every user message |
claude_code.tool_result |
tool_name, success, duration_ms | Every tool execution |
claude_code.api_error |
error, status_code, attempt | API failures and retries |
claude_code.tool_decision |
tool_name | Tool permission decisions |
In Grafana Cloud's Explore view, you can run custom queries:
Prometheus (metrics):
# Cost per session
sum by (session_id) (claude_code_cost_usage_USD_total)
# Token breakdown by model
sum by (model, type) (claude_code_token_usage_tokens_total)
# Most expensive sessions
topk(5, sum by (session_id) (claude_code_cost_usage_USD_total))
Loki (log events):
# All API requests
{service_name="claude-code"} | json | event_name="claude_code.api_request"
# Failed API calls
{service_name="claude-code"} | json | event_name="claude_code.api_error"
# Tool usage
{service_name="claude-code"} | json | event_name="claude_code.tool_result"
The full claude-settings-snippet.json in this repo contains all the settings. Here's what each one does:
| Setting | Value | Purpose |
|---|---|---|
CLAUDE_CODE_ENABLE_TELEMETRY |
1 |
Master switch — required |
OTEL_METRICS_EXPORTER |
otlp |
Send metrics via OTLP |
OTEL_LOGS_EXPORTER |
otlp |
Send log events via OTLP |
OTEL_EXPORTER_OTLP_PROTOCOL |
http/protobuf |
Use HTTP with protobuf encoding |
OTEL_EXPORTER_OTLP_ENDPOINT |
https://...grafana.net/otlp |
Your Grafana Cloud OTLP gateway |
OTEL_EXPORTER_OTLP_HEADERS |
Authorization=Basic ... |
Base64-encoded instanceId:apiKey |
OTEL_LOG_USER_PROMPTS |
1 |
Include prompt text in events |
OTEL_LOG_TOOL_DETAILS |
1 |
Include tool names in events |
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE |
cumulative |
Critical — Grafana Cloud rejects delta counters |
-
Metrics don't show up? Almost certainly a temporality issue. Make sure
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCEis set tocumulative. Without this, Grafana Cloud silently drops all counter metrics. -
Logs show up but metrics don't? Same issue — logs use a different protocol path than metrics, so logs can work while metrics are rejected.
-
Short sessions may not export metrics. The metrics flush interval is 60 seconds. If a session completes in under 60 seconds, the OTEL SDK may not flush in time. Longer sessions will always export properly.
-
Settings only apply to new sessions. After changing
~/.claude/settings.json, you must start a new Claude Code session. Existing sessions won't pick up the changes. -
The dashboard datasource must match. If your Grafana Prometheus datasource isn't named
grafanacloud-prom, you'll need to edit the dashboard JSON or select the correct datasource after import.
Zero. Grafana Cloud's free tier is generous:
- A typical Claude Code session generates a few hundred metrics data points and a few dozen log events
- At normal usage (10-20 sessions/day), you'd use less than 1% of the free tier's 10,000 metrics series
- Log events are similarly tiny compared to the 50 GB/month allowance
- The 14-day retention is plenty for tracking recent usage patterns
MIT
