Pro and Max subscribers get a progress bar. This gives you the full picture.
Claude Code writes detailed usage logs locally — token counts, models, sessions, projects — regardless of your plan. This dashboard reads those logs and turns them into charts and cost estimates. Works on API, Pro, and Max plans.
This fork adds cloud sync via Supabase for multi-device aggregation, plus an optional Cloudflare Worker for hosting the dashboard publicly (behind auth). Zero third-party Python packages — everything uses the standard library.
Original project: phuryn/claude-usage by The Product Compass Newsletter
Works on API, Pro, and Max plans — Claude Code writes local usage logs regardless of subscription type. This tool reads those logs and gives you visibility that Anthropic's UI doesn't provide.
Captures usage from:
- Claude Code CLI (
claudecommand in terminal) - VS Code extension (Claude Code sidebar)
- Dispatched Code sessions (sessions routed through Claude Code)
Not captured:
- Cowork sessions — these run server-side and do not write local JSONL transcripts
- Python 3.8+
- No third-party packages — uses only the standard library (
sqlite3,http.server,json,pathlib,urllib.request) - For the Cloudflare Worker (optional): Node.js 16+ and wrangler CLI
Anyone running Claude Code already has Python installed.
No pip install, no virtual environment, no build step.
git clone https://github.com/phuryn/claude-usage
cd claude-usage
python cli.py dashboard
git clone https://github.com/phuryn/claude-usage
cd claude-usage
python3 cli.py dashboard
On macOS/Linux, use
python3instead ofpythonin all commands below.
# Scan JSONL files and populate the database (~/.claude/usage.db)
python cli.py scan
# Show today's usage summary by model (in terminal)
python cli.py today
# Show all-time statistics (in terminal)
python cli.py stats
# Scan + open browser dashboard at http://localhost:8080
python cli.py dashboard
# Custom host and port via environment variables
HOST=0.0.0.0 PORT=9000 python cli.py dashboard
# Scan a custom projects directory
python cli.py scan --projects-dir /path/to/transcripts
The scanner is incremental — it tracks each file's path and modification time, so re-running scan is fast and only processes new or changed files.
By default, the scanner checks both ~/.claude/projects/ and the Xcode Claude integration directory (~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/projects/), skipping any that don't exist. Use --projects-dir to scan a custom location instead.
Sync usage data from multiple machines to a shared Supabase database and view aggregated stats in a cloud-powered dashboard. No third-party Python packages required — sync uses the Supabase REST API via urllib.request.
- Go to supabase.com and create a free account
- Create a new project (any name, e.g.
claude_usage) - Note your Project URL and anon key from Settings > API
In the Supabase SQL Editor, paste and run the contents of migrations/001_initial_schema.sql. This creates the turns and sessions tables with appropriate indexes and RLS policies.
Create ~/.claude/usage-sync.json:
{
"supabase_url": "https://YOUR_PROJECT.supabase.co",
"supabase_key": "your-anon-key-here"
}Alternatively, set environment variables: SUPABASE_URL and SUPABASE_KEY.
Repeat this step on every machine you want to sync.
Each machine is identified by its hostname. This is auto-detected on first sync and saved to ~/.claude/machine-id.
To override the name, add "machine_name" to your config:
{
"supabase_url": "https://YOUR_PROJECT.supabase.co",
"supabase_key": "your-anon-key-here",
"machine_name": "work-laptop"
}# Push local data to Supabase
python3 cli.py sync
# Scan + sync (auto-syncs if configured)
python3 cli.py scan
# Full rescan + full sync (daily safety net)
python3 cli.py scan --full
# Start the cloud dashboard (data from Supabase)
python3 cli.py dashboard --cloud
The cloud dashboard queries Supabase directly from the browser — the same HTML works whether served from a local Python server or a Cloudflare Worker.
The setup-launchd command auto-detects Python and installs two schedules:
python3 cli.py setup-launchd
This installs:
- Every 15 minutes (6am–6pm): incremental scan + smart sync (skips if no new data)
- Daily at 2:00 AM: full rescan + full sync (catches any drift)
To remove:
python3 cli.py uninstall-launchd
Note: On macOS, the system Python (
/usr/bin/python3) is sandboxed and cannot read~/.claude/from background jobs. The setup command automatically detects and uses Homebrew Python. If you only have the system Python, install Homebrew's:brew install python3.
- Device filter — view all devices aggregated or filter to a single machine (appears when 2+ devices are synced)
- Source indicator — green "Supabase Cloud" pill in the header confirms cloud data source
- Refresh controls — manual refresh button + auto-refresh toggle (15-min interval)
- Same charts and tables — all the same functionality as the local dashboard
- Incremental sync — only new turns are pushed; safe to run repeatedly
- Network-resilient — sync failures are retried automatically on the next run
Host the cloud dashboard on a public URL, protected by Cloudflare Access (Google OAuth, email allow-lists, etc.). The Worker is ~30 lines of code and runs on the free tier.
- Node.js 16+ and npm
- A Cloudflare account with a domain
npm install -g wrangler
- Configure credentials. Copy the template and fill in your values:
cp .env.example .env
# Edit .env with your Cloudflare API token and account ID
- Edit
worker/wrangler.toml. Uncomment and set your account ID and custom domain:
account_id = "your-account-id"
routes = [
{ pattern = "usage.example.com", custom_domain = true }
]- Deploy:
./worker/deploy.sh
- Add Supabase secrets (first time only):
cd worker
wrangler secret put SUPABASE_URL # paste your Supabase project URL
wrangler secret put SUPABASE_KEY # paste your Supabase anon key
- Protect with Cloudflare Access. In the Cloudflare Zero Trust dashboard, create an Access application for your subdomain with your preferred identity provider (Google, GitHub, email OTP, etc.).
After updating dashboard.html, redeploy with:
./worker/deploy.sh
The custom domain and secrets persist across deploys — you only set them up once.
Claude Code writes one JSONL file per session to ~/.claude/projects/. Each line is a JSON record; assistant-type records contain:
message.usage.input_tokens— raw prompt tokensmessage.usage.output_tokens— generated tokensmessage.usage.cache_creation_input_tokens— tokens written to prompt cachemessage.usage.cache_read_input_tokens— tokens served from prompt cachemessage.model— the model used (e.g.claude-sonnet-4-6)
scanner.py parses those files and stores the data in a SQLite database at ~/.claude/usage.db.
dashboard.py serves a single-page dashboard on localhost:8080 with Chart.js charts (loaded from CDN). It supports model and device filtering with bookmarkable URLs. The bind address and port can be overridden with HOST and PORT environment variables (defaults: localhost, 8080).
sync.py pushes local data to Supabase using the PostgREST API. It uses a high-water mark strategy to track what has already been synced, so only new data is pushed on each run.
Costs are calculated using Anthropic API pricing as of April 2026 (claude.com/pricing#api).
Only models whose name contains opus, sonnet, or haiku are included in cost calculations. Local models, unknown models, and any other model names are excluded (shown as n/a).
| Model | Input | Output | Cache Write | Cache Read |
|---|---|---|---|---|
| claude-opus-4-6 | $5.00/MTok | $25.00/MTok | $6.25/MTok | $0.50/MTok |
| claude-sonnet-4-6 | $3.00/MTok | $15.00/MTok | $3.75/MTok | $0.30/MTok |
| claude-haiku-4-5 | $1.00/MTok | $5.00/MTok | $1.25/MTok | $0.10/MTok |
Note: These are API prices. If you use Claude Code via a Max or Pro subscription, your actual cost structure is different (subscription-based, not per-token).
Original project by phuryn / The Product Compass Newsletter. Cloud sync and Cloudflare Worker deployment added in this fork.

