English | 日本語
codex-usage-dashboard is a local, single-binary dashboard for Codex and Claude
Code usage, cost estimates, and attribution.
It shows Codex and Claude Code on separate dashboard tabs, with usage history, token totals, estimated USD cost, and attribution breakdowns. Codex USD cost is estimated from credits at 1000 credits = $40; Claude Code USD cost is calculated from Claude Code telemetry using the Claude API pricing table.
The screenshots below show a 12-hour range at 5-minute grain.
- Codex tab: Codex OTLP export configured (see Configure Codex OTLP)
- Codex usage % gauges: Codex CLI installed and signed in
- Claude Code tab: Claude Code telemetry configured (see Configure Claude Code OTLP)
The dashboard can run with only one tool enabled. Set
CODEX_USAGE_DASHBOARD_CODEX_ENABLED=false on machines that do not use Codex, or
CODEX_USAGE_DASHBOARD_CLAUDE_ENABLED=false on machines that do not use Claude
Code.
The prebuilt binary is macOS only (Apple Silicon). Download it from the Releases page, then run it:
unzip codex-usage-dashboard-macos-arm64.zip
chmod +x codex-usage-dashboard
./codex-usage-dashboardThe release binary is not currently signed or notarized. If macOS blocks it with "Apple could not verify" and you trust the downloaded file, remove the quarantine attribute and run it again:
xattr -d com.apple.quarantine codex-usage-dashboard
./codex-usage-dashboardOn another platform, or want to build it yourself? Build from source — see
dev_docs/development.md.
Open:
http://127.0.0.1:4318/
Use the top-bar tabs to switch between Codex and Claude Code. The range selector supports relative windows, the current Codex 5h usage window, and a custom from/to range.
Most charts and usage tables have a local Cost / Tokens toggle. The toggle is per panel, so you can compare one breakdown by USD cost while keeping another in raw token counts.
By default the app listens only on localhost:
- OTLP gRPC:
127.0.0.1:4317 - HTTP dashboard and OTLP/HTTP protobuf:
127.0.0.1:4318
The local database is created at:
data/codex-usage-dashboard.sqlite
relative to the directory where you run the binary.
The basic setup points Codex's OTLP log export directly at this dashboard's gRPC
receiver. Edit ~/.codex/config.toml:
[otel]
exporter = { otlp-grpc = { endpoint = "http://127.0.0.1:4317" } }Restart Codex after changing the config. New Codex activity should start filling the dashboard within about a minute.
Keep this dashboard process running while you use Codex or Claude Code to capture new OTLP events. Events emitted while it is stopped are not backfilled.
Claude Code sends OTLP log/events to the same local gRPC receiver. Token and cost charts are populated from Claude Code telemetry.
For persistent setup, edit ~/.claude/settings.json and merge these entries into
the existing env object:
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://127.0.0.1:4317"
}
}Restart Claude Code, or start a new session, after changing the settings file.
For a one-off session, set the same values in the shell before launching
claude:
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317
claudeClaude Code cost is calculated from the token counts in its telemetry. If Claude
Code also reports its own cost_usd, the dashboard keeps that value separately
for comparison.
For the full Claude Code telemetry configuration surface, see the Claude Code Monitoring docs.
This dashboard listens on the standard OTLP ports (gRPC :4317, HTTP :4318) so
Codex and Claude Code can point at it directly. If you already run an
OpenTelemetry Collector on those ports,
keep your tools pointed at the collector, fan out a copy to this dashboard, and
move the dashboard off the standard ports.
Quarkus reads a .env file from the working directory, so put the overrides
there:
# .env
QUARKUS_GRPC_SERVER_PORT=14317
QUARKUS_HTTP_PORT=14318Then have the collector send OTLP/HTTP protobuf to http://127.0.0.1:14318/v1/logs
(or gRPC to :14317).
The dashboard is local-only by default. It has no authentication, and the
raw-log drill-down (/api/events/{id}/raw) returns verbatim OTLP records that can
include working directories, conversation ids, host names, and account metadata.
Exposing it on your LAN gives every device on the network unauthenticated read
access to that data — only do this on a trusted network.
To intentionally expose it on your LAN:
QUARKUS_HTTP_HOST=0.0.0.0 \
QUARKUS_GRPC_SERVER_HOST=0.0.0.0 \
./codex-usage-dashboardThen open http://<machine-ip>:4318/ from another device.
Quarkus reads a .env file from the working directory. See
.env.example for copyable defaults. Useful environment
variables:
# Tool-specific ingestion flags
CODEX_USAGE_DASHBOARD_CODEX_ENABLED=true
CODEX_USAGE_DASHBOARD_CLAUDE_ENABLED=true
# Ports / bind addresses
QUARKUS_HTTP_HOST=127.0.0.1
QUARKUS_HTTP_PORT=4318
QUARKUS_GRPC_SERVER_HOST=127.0.0.1
QUARKUS_GRPC_SERVER_PORT=4317
# Local storage
QUARKUS_DATASOURCE_JDBC_URL='jdbc:sqlite:data/codex-usage-dashboard.sqlite?journal_mode=WAL&busy_timeout=10000'
# Local telemetry retention
CODEX_USAGE_DASHBOARD_RETENTION_EVERY=1h
CODEX_USAGE_DASHBOARD_RETENTION_OTEL_LOG_RECORDS=14d
CODEX_USAGE_DASHBOARD_RETENTION_ANNOTATED_EVENTS=365d
CODEX_USAGE_DASHBOARD_RETENTION_USAGE_SAMPLES=365d
# Codex local data directory
CODEX_DB_DIR="$HOME/.codex"
CODEX_BIN=codex
# Receive-time drop filter for noisy OTLP log records
CODEX_USAGE_DASHBOARD_INGEST_DROP_EVENT_KINDS='^response[.].+[.]delta$'
# Advanced polling / batch tuning
CODEX_USAGE_DASHBOARD_ANNOTATE_EVERY=60s
CODEX_USAGE_DASHBOARD_ANNOTATE_BATCH_SIZE=500
CODEX_USAGE_DASHBOARD_USAGE_EVERY=60sSet CODEX_USAGE_DASHBOARD_CODEX_ENABLED=false on machines without Codex. This
ignores Codex OTLP logs and skips Codex usage polling, so the app will not try
to launch codex. Set CODEX_USAGE_DASHBOARD_CLAUDE_ENABLED=false to ignore
Claude Code OTLP logs. Disabled tools are also hidden from the dashboard tool
switcher.
Retention is enforced independently for each kind of local data:
- Raw OTLP log records: the original Codex and Claude Code OTLP log payloads used by the raw event drill-down. These are usually the largest records. The configured retention age is a cleanup threshold, not a guarantee that every older record disappears immediately.
- Dashboard history: parsed token, cost, trigger, and error data used by charts and tables.
- Codex usage samples: periodic Codex rate-limit percentage snapshots.
Set any retention value to 0 or disabled to keep that data type indefinitely.
Deleting old raw OTLP records does not remove already-built chart history, but
raw event drill-down for those older events will no longer be available. SQLite
may reuse freed pages without immediately shrinking the database file; run
VACUUM manually if you need to compact the file on disk.
By default, receive-time ingestion drops high-volume Codex streaming delta records
whose event.kind matches ^response[.].+[.]delta$. Those rows do not carry token
usage and can be much noisier than completed request records. Set
CODEX_USAGE_DASHBOARD_INGEST_DROP_EVENT_KINDS to an empty value if you need to
store every received OTLP log record.
Supported:
- OTLP/gRPC on
:4317 - OTLP/HTTP protobuf on
:4318/v1/logs - gzip-compressed OTLP/HTTP protobuf bodies
- Claude Code OTLP log
api_requestrecords with token andcost_usdfields
Dashboard charts are based on OTLP logs. Metrics and traces may be accepted by the receiver, but they are not shown in dashboard charts.
Not supported:
- OTLP/HTTP JSON (
Content-Type: application/json)
OTLP/HTTP JSON requests return 415 Unsupported Media Type so misconfigured
exporters do not appear to succeed while silently dropping data. Make sure any
OTLP/HTTP exporter sends protobuf (encoding: proto), not JSON.
Developer-facing notes live in dev_docs/. Start with:
Licensed under the Apache License, Version 2.0. See NOTICE
for attribution of bundled third-party components (Apache ECharts).

