Chrome extension (MV3, plain JS, no build) that shows your AI subscription usage limits and API credits in one popup, using the sessions you're already logged in with. No API keys, no analytics, no remote code.
- Open
chrome://extensions. - Turn on Developer mode (top right).
- Click Load unpacked and pick this folder (the one with
manifest.json). - Pin TokenWatch from the puzzle-piece menu and click it.
After editing any file, click the ↻ reload icon on the TokenWatch card in chrome://extensions.
| Service | Requests | Auth |
|---|---|---|
| Claude | GET /api/organizations → picks the org with chat capability; plan from claude_pro / claude_maxGET /api/organizations/{uuid}/usage → limits[] (kind, percent, resets_at) |
cookies only |
| ChatGPT | GET /api/auth/session → accessToken (kept in memory only, max 10 min)GET /backend-api/wham/usage → rate_limit.primary_window (5-hour) / secondary_window (weekly), labeled by limit_window_seconds: used_percent, reset_at (unix seconds) |
Authorization: Bearer <accessToken> |
| Gemini | GET /app (HTML) → XSRF token SNlM0e (kept in memory only, max 10 min)POST /_/BardChatUi/data/batchexecute?rpcids=jSf9Qc&rt=c, form body f.req=[[["jSf9Qc","[]",null,"generic"]]]&at=<token> → [2, [[?, fractionUsed, kind (1 = current, 2 = weekly), [[resetUnixSeconds, nanos]]], …], false] |
cookies + at token |
| Claude API | GET /api/organizations on platform.claude.com → picks the org with api capabilityGET /api/organizations/{uuid}/current_spend → amount (cents), resets_atGET /api/organizations/{uuid}/spend_limits → spend_limits[].limit_usd (cents; despite the name), enforced_limit_usd (tier cap)GET /api/organizations/{uuid}/prepaid/credits → amount (cents) |
cookies only |
| OpenAI API | Runs inside an open platform.openai.com tab: reads localStorage["oai-auth:onboard"].accessToken, POST api.openai.com/v1/dashboard/onboarding/login → user.session.sensitive_id (sess-…)GET api.openai.com/v1/dashboard/billing/credit_grants → total_granted, total_used, total_available (dollars) |
page tokens; never leave the tab |
Claude and ChatGPT show 5-hour limit and Weekly limit. Claude Max also shows per-model weekly limits, such as Weekly limit (Fable), and its tier, such as Max 5x. ChatGPT Pro has no 5-hour limit, so it shows only Weekly limit. Gemini shows Current limit and Weekly limit, which are the two bars on gemini.google.com/usage; Gemini doesn't say how long its current window is. Gemini's plan isn't shown because it comes from a request that hasn't been captured yet. ChatGPT's numbers are the "Plan limits" on chatgpt.com/settings/usage?tab=overview, which ChatGPT says are shared across Codex, Work, Workspace Agents and ChatGPT for Excel. Regular chat conversations are not included.
Claude API shows Monthly spend against your own spend limit (or the tier cap when none is set), which is the bar on platform.claude.com/dashboard, and Credit balance, which is the total on Settings → Billing, promotional credits included. OpenAI API shows Credit balance (the "Credit remaining" on platform.openai.com/home) with a bar for how much of your granted credit is used. It only refreshes while a platform.openai.com tab is open, because the dashboard login is kept in that page rather than in cookies. For that reason it's off by default; turn it on in Options.
storage: settings and parsed results (chrome.storage.local); the Debug raw JSON goes inchrome.storage.session(memory, cleared when Chrome closes).alarms: background refresh (default 15 min, minimum 5).scripting: the fallback. When a background fetch fails (cookies not sent, Cloudflare, missing page headers), the same request is run inside an already-open tab of that site (MAIN world). The extension never opens tabs on its own. It finds the tab throughchrome.tabs.querywith a URL filter, which the host permissions already allow, so thetabspermission isn't needed.- Host permissions:
https://claude.ai/*,https://chatgpt.com/*,https://gemini.google.com/*,https://platform.claude.com/*,https://platform.openai.com/*only.
Choose which services appear, and their order in the popup, in Options → Services to show. Options → Toolbar badge shows the highest % used across all services by default. Tick providers, metrics (such as Weekly limit, which then covers every ticked provider's weekly limit), or both to narrow it; the badge shows the highest of what's ticked.
Fetches happen when the popup opens (the cache is reused if it's under 1 minute old), when you click Refresh, and on the alarm. Any non-OK result, including HTTP 429, backs off automatically: 5 → 10 → 20 … minutes, capped at 2 h. The manual Refresh button ignores backoff.
node --test tests/parsers.test.mjs: parser tests built from the captured responses.
- "Not logged in": log in on the site (the button opens it), then press Refresh. If you are logged in, Chrome may not have sent your cookies to the background request. Keep a tab of the site open and press Refresh so the in-tab fallback runs.
- 401 / 403: the session expired, or the org changed (Claude re-discovers its org on the next fetch after a 403/404). For ChatGPT, a 401 gets one automatic retry with a fresh token. If it keeps failing, reload the site tab and refresh.
- Cloudflare challenge ("Blocked by a Cloudflare check"): open or reload the site in a tab, complete any check, then Refresh. The in-tab fallback reuses the cleared session.
- "Couldn't parse" / endpoint changed:
- Tick Debug in the popup to see the raw JSON from the last fetch.
- Open the site's usage page with DevTools → Network → Fetch/XHR and find the new request (Claude: Settings → Usage, look for
usage; ChatGPT: Settings → Usage, look forwham/usage; Gemini: Settings → Usage limits, look forbatchexecutewithrpcids=jSf9Qc). - Edit only that service's adapter:
adapters/claude.js,adapters/chatgpt.js,adapters/gemini.js,adapters/claude-api.jsoradapters/openai-api.js. The URLs are at the top offetchUsage(); the mapping is inparseUsage(). Both must return the same normalized shape. - Update the sample in
tests/parsers.test.mjs, run the tests, and reload the extension.