GitHub - stempest/claude-usage: A local dashboard for tracking your Claude Code token usage, costs, and session history. Pro and Max subscribers get a progress bar. This gives you the full picture. · GitHub
Skip to content

stempest/claude-usage

 
 

Repository files navigation

Claude Code Usage Dashboard — Cloud Sync Fork

License: MIT claude-code

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

Claude Usage Dashboard


What this tracks

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 (claude command 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

Requirements

  • 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.

Quick Start

No pip install, no virtual environment, no build step.

Windows

git clone https://github.com/phuryn/claude-usage
cd claude-usage
python cli.py dashboard

macOS / Linux

git clone https://github.com/phuryn/claude-usage
cd claude-usage
python3 cli.py dashboard

Usage

On macOS/Linux, use python3 instead of python in 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.


Cloud Sync (Multi-Device)

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.

1. Create a Supabase project

  1. Go to supabase.com and create a free account
  2. Create a new project (any name, e.g. claude_usage)
  3. Note your Project URL and anon key from Settings > API

2. Apply the database schema

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.

3. Configure credentials

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.

4. Machine identity

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"
}

5. Sync and view

# 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.

6. Automatic sync (macOS)

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.

Cloud dashboard features

  • 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

Cloudflare Worker (Optional)

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.

Prerequisites

  • Node.js 16+ and npm
  • A Cloudflare account with a domain
  • npm install -g wrangler

Setup

  1. Configure credentials. Copy the template and fill in your values:
cp .env.example .env
# Edit .env with your Cloudflare API token and account ID
  1. 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 }
]
  1. Deploy:
./worker/deploy.sh
  1. 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
  1. 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.).

Redeploying after changes

After updating dashboard.html, redeploy with:

./worker/deploy.sh

The custom domain and secrets persist across deploys — you only set them up once.


How it works

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 tokens
  • message.usage.output_tokens — generated tokens
  • message.usage.cache_creation_input_tokens — tokens written to prompt cache
  • message.usage.cache_read_input_tokens — tokens served from prompt cache
  • message.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.


Cost estimates

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).


Files

File Purpose
scanner.py Parses JSONL transcripts, writes to ~/.claude/usage.db
dashboard.py HTTP server serving dashboard.html
dashboard.html Single-page HTML/JS dashboard (shared by Python server and Worker)
cli.py scan, sync, today, stats, dashboard, setup-launchd commands
config.py Cloud sync configuration and machine identity
sync.py Pushes local data to Supabase via PostgREST API
migrations/001_initial_schema.sql Supabase database schema
launchd/ macOS launchd plist templates (used by setup-launchd)
worker/ Cloudflare Worker source and deploy script

Credits

Original project by phuryn / The Product Compass Newsletter. Cloud sync and Cloudflare Worker deployment added in this fork.

About

A local dashboard for tracking your Claude Code token usage, costs, and session history. Pro and Max subscribers get a progress bar. This gives you the full picture.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

Contributors

Languages

  • Python 69.7%
  • HTML 28.9%
  • Other 1.4%