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.

Native · zero config

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
Native · standard OTEL env

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
Native · prefixed env

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.

Native · config.toml

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.

Native · standard OTEL env

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
Native · explicit opt-in

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.

DIY · for any other tool

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 raw column.

Tool not on this list? hello@scoreflow.dev or the feedback widget in the corner. We add what people actually use.