Docs · bring your own OTEL
Connect any OTEL-emitting CLI
Scoreflow’s collector speaks standard OTLP/HTTP with JSON bodies. Any OpenTelemetry client that can set three env vars (or the equivalent in a config file) can ingest into your Scoreflow team. Below: the five CLIs we’ve verified against their official docs.
The three env vars
Every OTLP exporter — Node, Python, Go, Rust — reads these. Grab your ingest token from /me or from ~/.scoreflow/config.json after running scoreflow init.
export OTEL_EXPORTER_OTLP_ENDPOINT=https://collect.scoreflow.dev export OTEL_EXPORTER_OTLP_PROTOCOL=http/json export OTEL_EXPORTER_OTLP_HEADERS=X-ScoreFlow-Token=sk_prod_XXXX export OTEL_SERVICE_NAME=your-tool-name
Important: http/json is required. Our collector returns 415 Unsupported Media Type on protobuf.
Claude Code (Anthropic)
scoreflow init wires this for you — sets the env vars in your shell rc and installs the Claude Code Stop hook. Nothing else to do. The CLI + dashboard + MCP server all work out of the box.
npm i -g @scoreflow/cli scoreflow init # signs you in, wires everything
opencode (sst)
opencode ships OTEL export out of the box since v1.0.134. Drop the three env vars in your shell rc and launch as normal — no config file changes.
export OTEL_EXPORTER_OTLP_ENDPOINT=https://collect.scoreflow.dev export OTEL_EXPORTER_OTLP_PROTOCOL=http/json export OTEL_EXPORTER_OTLP_HEADERS=X-ScoreFlow-Token=sk_prod_XXXX export OTEL_SERVICE_NAME=opencode opencode # events flow to Scoreflow
Gemini CLI (Google)
Gemini CLI uses prefixed env vars (not the OTEL_EXPORTER_*). Set target to local to skip their Google Cloud path and hit ours directly. Both grpc and http protocols supported — we need http.
export GEMINI_TELEMETRY_ENABLED=true export GEMINI_TELEMETRY_TARGET=local export GEMINI_TELEMETRY_OTLP_ENDPOINT=https://collect.scoreflow.dev export GEMINI_TELEMETRY_OTLP_PROTOCOL=http # The standard auth header still applies — Scoreflow reads it from the # OTLP request headers the Gemini exporter adds: export OTEL_EXPORTER_OTLP_HEADERS=X-ScoreFlow-Token=sk_prod_XXXX gemini
Alternative: add the same values to .gemini/settings.json under a telemetry block. The env-var path is simpler for throwaway sessions.
OpenAI Codex CLI
Codex reads its telemetry config from ~/.codex/config.toml. Telemetry is off by default — flip it on with an [otel] block. Keep log_prompts = false (the default) — Scoreflow does not want prompt content.
# ~/.codex/config.toml [otel] enabled = true exporter = "otlp-http" endpoint = "https://collect.scoreflow.dev" protocol = "http/json" environment = "prod" log_prompts = false [otel.headers] "X-ScoreFlow-Token" = "sk_prod_XXXX"
Headers support env-var interpolation if you prefer to keep the token out of the file — see the Codex advanced config docs.
Goose (Block)
Goose reads the standard OpenTelemetry SDK env vars — same three as opencode, plus an explicit exporter selector. Works with gRPC or HTTP/JSON; we need HTTP/JSON.
export OTEL_EXPORTER_OTLP_ENDPOINT=https://collect.scoreflow.dev export OTEL_EXPORTER_OTLP_PROTOCOL=http/json export OTEL_EXPORTER_OTLP_HEADERS=X-ScoreFlow-Token=sk_prod_XXXX export OTEL_SERVICE_NAME=goose export OTEL_TRACES_EXPORTER=otlp export OTEL_METRICS_EXPORTER=otlp export OTEL_LOGS_EXPORTER=otlp goose session
GitHub Copilot CLI
Copilot CLI ships OTel support but keeps it off by default with zero overhead. Set COPILOT_OTEL_ENABLED=1 to enable. By design, no prompt content or tool arguments are captured — only metadata (model names, token counts, durations). W3C Trace Context propagates automatically.
export COPILOT_OTEL_ENABLED=1 export OTEL_EXPORTER_OTLP_ENDPOINT=https://collect.scoreflow.dev export OTEL_EXPORTER_OTLP_PROTOCOL=http/json export OTEL_EXPORTER_OTLP_HEADERS=X-ScoreFlow-Token=sk_prod_XXXX export OTEL_SERVICE_NAME=copilot-cli # Defaults we WANT: # OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=false (Copilot default — leave alone) gh copilot
Do not set OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true. Copilot’s default is off; flipping it on would send prompt content we do not store anyway, wasting bandwidth.
Roll your own
If your tool exposes a hook (a Stop hook, a shell alias, a git post-commit hook…), you can emit OTLP/HTTP JSON directly from curl. The collector accepts the standard resourceLogs envelope:
curl -X POST https://collect.scoreflow.dev/v1/logs \
-H "Content-Type: application/json" \
-H "X-ScoreFlow-Token: sk_prod_XXXX" \
-d '{
"resourceLogs": [{
"resource": {"attributes":[{"key":"service.name","value":{"stringValue":"my-tool"}}]},
"scopeLogs": [{
"logRecords": [{
"timeUnixNano": "'$(date +%s%N)'",
"body": {"stringValue": "user_prompt"},
"attributes": [
{"key":"event.name","value":{"stringValue":"user_prompt"}},
{"key":"user.email","value":{"stringValue":"you@example.com"}}
]
}]
}]
}]
}'Attribution: user.email ties the event to a Scoreflow user. Anything else becomes metadata on the stored event.
Privacy boundaries
- Send only metadata: prompt length, token counts, tool names, session shape. Never prompt or response content.
- Events live in ClickHouse on Hetzner Frankfurt (EU).
- Raw events: 90-day retention. Daily aggregates kept indefinitely while your account is active.
- If a CLI inadvertently sends prompt text in an attribute, we drop it at normalization. Report a bug if you see content in the
rawcolumn.
Tool not on this list? hello@scoreflow.dev or the feedback widget in the corner. We add what people actually use.