Claude Code integration

Claude Code (Anthropic's CLI) emits OpenTelemetry telemetry when the CLAUDE_CODE_ENABLE_TELEMETRY environment variable is set. Point its OTLP exporter at ActivityLog and you get per-session activity, token usage, model breakdown, and tool calls.

This is currently the only live Claude data path — there is no Anthropic-side usage import for subscription accounts. Customers on the paid Anthropic API can also forward usage via the OTel hook the same way.

What you get

Visibility Field on the Message row
Which model was used model (e.g. claude-opus-4-7)
Input tokens inputTokens
Output tokens outputTokens
Cache read tokens cacheReadTokens
Cache creation tokens cacheCreateTokens
Cost (microcents = USD × 10⁶) costMicrocents
User / session metadata.user.id / metadata.session.id
Tool calls child messages of the parent generation span
Prompt + completion body (Enterprise; truncated on Pro/Free)

This is the same gen_ai.* first-party promotion that applies to any OTLP source — see 51-ingest-otlp.md.

Setup

1. Mint a token

Portal → Systems → New System named claude-code (or whatever) → New Token → 5-year retention recommended → Generate.

2. Set environment variables

On every machine running Claude Code:

export CLAUDE_CODE_ENABLE_TELEMETRY=1

# OTLP exporter destinations
export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://api.activitylog.com/api/v1/otlp/v1/logs
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.activitylog.com/api/v1/otlp/v1/traces
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

# Auth — bearer token on every export
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer al_REPLACE_WITH_YOUR_TOKEN"

# Identify this user / service
export OTEL_RESOURCE_ATTRIBUTES="service.name=claude-code,user.name=$USER"

Restart any Claude Code sessions to pick up the change.

3. Verify

Run any Claude Code command:

claude "what files are in this directory?"

Within a few seconds you should see new entries on the portal Messages page with serviceName: "claude-code" and type: "ai.generation" (or similar).

Cost queries

Once data is flowing, you can query cost rolled up by model / user / day:

curl "https://api.activitylog.com/api/v1/messages/aggregate?type=ai.generation&groupBy=model&metric=sum(costMicrocents)&from=2026-05-01" \
  -H "Authorization: Bearer YOUR_JWT_HERE"

The Claude Code report pack (planned — see 90-reports.md) will turn these queries into a dashboard.

Multi-user setups

If multiple developers run Claude Code on their workstations and you want per-user attribution:

  • Set user.name=$USER (or OTEL_RESOURCE_ATTRIBUTES=user.id=alice@example.com) on each machine.
  • All sessions emit under the same token — separation is at the resource-attribute layer.
  • Aggregate by metadata.user.name in queries:
    ?type=ai.generation&groupBy=metadata.user.name&metric=sum(costMicrocents)
    

If you'd prefer hard isolation (each user's data goes to a separate system), mint one token per user and configure OTEL_EXPORTER_OTLP_HEADERS accordingly. Costs are higher in admin overhead but the boundary is real.

Why not pull from the Anthropic Usage API?

The Anthropic Usage Report API is paid-API-only — it doesn't cover Claude subscription usage (Pro / Max plans). Fyin's own use of Claude Code is on subscriptions, so the OTel hook is the only signal source. For paid-API customers the Usage Report API would technically work, but the OTel path is more granular (per-tool, per-session) and avoids a polling worker.

A planned claude-usage import worker would have pulled from the Usage API; that work is shelved until a customer needs it.

Status

Live — this is the recommended setup as of 2026-05. The Fyin team uses it themselves for tracking Claude Code spend.

What's next

Goal Doc
The OTLP receiver behavior 51-ingest-otlp.md
Query token usage and cost 60-query-api.md
Claude Code report pack status 90-reports.md

Troubleshooting

Claude Code says telemetry is enabled but nothing arrives. Check OTEL_EXPORTER_OTLP_HEADERS formatting — the SDK expects key1=value1,key2=value2 not standard HTTP header syntax. The leading Authorization=Bearer has no extra space inside.

Per-user costMicrocents doesn't match my Anthropic invoice. Claude Code reports the per-request cost the local SDK calculated from its model price table. This drifts from the invoice by promotional credits, regional pricing, and rounding. It's directionally accurate — don't reconcile to the cent.