token-activity-widget
v0.2.0
Published
White-label React activity heatmap grid plus local sync CLI for Claude, Codex, and OpenCode usage
Maintainers
Readme
token-activity-widget
White-label React activity heatmap grid plus a local sync CLI for Claude, Codex, and OpenCode usage.
Package: npmjs.com/package/token-activity-widget
What this is
- A grid-only activity heatmap you can drop into your own website chrome
- A white-label React surface: no built-in header, avatar, streak card, or profile frame
- A local CLI that reads real activity from your machine and writes normalized widget data into your app
- Two website flows:
Import JSON: simplest and private-firstFetch URL: runtime fetch from a static JSON file or API URL
What this is not
- It does not read local logs from the browser
- It does not ask website visitors for Claude, Codex, or OpenCode tokens
- It does not require your users to log into a separate leaderboard website
The browser package only renders data you give it. Real activity collection stays in the CLI.
Install
npm install token-activity-widgetRequirements:
react >= 18react-dom >= 18node >= 18
Quick Start: Bare Grid
import { ActivityGrid, type ActivityWidgetDay } from 'token-activity-widget'
const activity: ActivityWidgetDay[] = [
{
date: '2026-06-01',
input_tokens: 1200,
output_tokens: 800,
cache_creation_input_tokens: 0,
cache_read_input_tokens: 0,
messages: 4,
sessions: 2,
},
]
export function SiteSection() {
return (
<div style={{ maxWidth: 840, padding: 16 }}>
<ActivityGrid activity={activity} preset="night" />
</div>
)
}Quick Start: Import Data Object
import { ActivityWidgetFromData, type ActivityWidgetData } from 'token-activity-widget'
const data: ActivityWidgetData = {
publicId: 'demo-user',
preset: 'night',
lastSyncedAt: new Date().toISOString(),
activity: [],
}
export function CustomWidget() {
return <ActivityWidgetFromData data={data} />
}Quick Start: Fetch Any JSON URL
import { ActivityWidget } from 'token-activity-widget'
export function PortfolioWidget() {
return (
<ActivityWidget
url="/token-activity-widget.json"
preset="paper"
/>
)
}ActivityWidget accepts any URL that returns JSON matching ActivityWidgetData.
That URL can be:
- a static file like
/token-activity-widget.json - your own API route
- any other same-origin or allowed cross-origin JSON endpoint
The fetch layer still tolerates richer legacy payloads with extra fields, but only the grid data is used.
Real Data Setup
The CLI is the real-data bridge.
Run this inside the website repo where you want to embed the grid:
npx token-activity-widget initThat command:
- detects a supported app
- explains the two setup modes in plain language
- writes
token-activity-widget.config.json - scaffolds a starter component
- adds a
token-activity:syncscript to your app - writes an agent prompt you can paste into Codex or Claude for final placement/styling
Then generate real data:
npx token-activity-widget syncOr after install:
npm run token-activity:syncThe Two Website Flows
1. Import JSON
Recommended for most people.
What the user does:
- Run
npx token-activity-widget init - Let it scaffold the component and config
- Run
npx token-activity-widget sync - Import the generated component into their app page
- Re-run sync whenever they want fresh data, then redeploy
What gets generated:
- a JSON data file
- a typed generated module for direct app imports
- a
TokenActivityGridcomponent usingActivityWidgetFromData
2. Fetch URL
Best when the site should fetch the widget data at runtime.
What the user does:
- Run
npx token-activity-widget init --mode fetch-url - Let it scaffold a public JSON target and component
- Run
npx token-activity-widget sync - Render the generated component
- Re-run sync whenever they want fresh public JSON
What gets generated:
- a public JSON file like
public/token-activity-widget.json - a
TokenActivityGridcomponent usingActivityWidget url="..."
The default fetch target is a same-site static JSON file, but advanced users can later swap the URL to their own API route without changing the widget contract.
Supported Local Sources
The CLI reads local usage history from these defaults:
- Claude:
~/.claude/projects/**/*.jsonl - Codex:
~/.codex/logs_2.sqlite - OpenCode:
~/.local/share/opencode/opencode.db
You can override those paths in token-activity-widget.config.json if your setup differs.
Framework Support
v1 scaffolding officially supports:
- Next.js App Router
- Vite + React
Customization
All public components support:
presetthemeclassNameshowLabelsshowTooltip
This package is intentionally white-label. Wrap the grid in your own layout, typography, and brand chrome.
Theme API
type ActivityWidgetTheme = {
text: string
muted: string
tooltipBackground: string
tooltipText: string
activityScale: [string, string, string, string, string]
}Pass theme as a partial object. Missing fields fall back to the chosen preset.
Built-in presets:
nightarcadepaper
Public API
ActivityGridActivityWidgetFromDataActivityWidgetfetchActivityWidgetDatagetPresetThememergeWidgetThemetype ActivityWidgetThemetype ActivityWidgetDatatype ActivityWidgetDaytype ActivityWidgetPreset
Sandbox
Use the sandbox to test the package like a real consumer:
npm install
npm run sandbox:install
npm run sandbox:devThe sandbox includes:
- bare
ActivityGridmode - direct-data mode
- fetched URL mode
- preset, theme, width, label, and tooltip controls
- a local mock URL for testing fetch success and error states
Validation
npm test
npm run verify
npm run verify:all
npm run sandbox:smokeverify:all checks the package shape and confirms the sandbox builds against the local package.
Examples
See examples/ for:
- bare grid usage
- direct-data usage
- fetched JSON URL usage
