Usage Monitor
A VS Code extension that shows daily and weekly usage for Claude and Codex
inside the editor — across as many accounts as you like, read from your own
signed-in browser sessions, with no API keys and no telemetry.
How it works
Claude and ChatGPT/Codex put their usage data behind Cloudflare bot-protection,
so replaying cookies from Node.js does not work. Instead, Usage Monitor opens a
controlled browser window (your installed Chrome or Edge, reused via
Playwright — nothing is downloaded) where you sign in once. That login is
kept in a dedicated, isolated browser profile on disk. On refresh, the extension
navigates that browser to the provider's usage page and reads the provider's own
usage JSON response — no scraping of fragile HTML, no credentials handled by the
extension itself.
Features
- A sidebar view in its own activity-bar container with one card per
account: usage bars, a status chip, last-refreshed time, and per-account
Sign in / Refresh / Rename / Disconnect / Remove actions
- Multiple accounts per provider — sign in to several Claude and several
Codex accounts, each with your own label and a fully isolated browser profile
- Collapsible cards, in the order you choose — fold away the accounts you
are not watching and move the one you care about to the top. Both stick across
reloads, and a collapsed account is never refreshed
- Streaming refresh: every account is captured in its own browser at the
same time, and each card fills in the moment that browser has the data, so a
slow or challenged login never holds up the rest
- Every window on a budget pace bar — session and weekly alike: one bar split
into a segment per unit of time left before the reset (hours for the 5-hour
session window, days for weekly ones), with a marker for where consumption
should have reached by now and a one-line verdict (
5% extra, 2% over,
CRITICAL)
- The scheduled reset date and time next to each window's countdown, when
the provider exposes it
- A status-bar summary (e.g.
Claude 42% · Codex 71%) that turns amber near
a limit
- First-class UI states: signed-out, expired-session, rate-limited, unsupported,
layout-changed, and error — never a silent zero
- No API keys; the extension never reads or stores your cookies or tokens (the
isolated browser profile holds the session)
- Strict webview CSP with nonced local scripts; no remote requests from the view
- Optional, conservative auto-refresh (off by default)
First run
- Open the Usage Monitor view from the activity bar (bar-chart icon).
- Click Sign in on the Claude and/or Codex card. A browser window opens —
log in to the provider as normal, then return to VS Code.
- Click Refresh. The extension reads your current usage.
You only sign in once per account; the session persists.
Multiple accounts
Use + Claude account / + Codex account at the bottom of the view (or the
+ button in the view title, or Usage Monitor: Add Account) to add another
login. Each account gets its own browser profile directory, so a personal and a
work Claude account never share cookies.
Rename on a card sets the label shown on the card, in the status bar and in
every account picker — for example Claude · work and Claude · personal.
Disconnect signs an account out but keeps it in the list; Remove deletes
its browser profile and forgets it entirely.
Move to top puts an account first, which is also where it appears in the
status bar. Click a card's header to fold it shut; click again to open it. Both
the order and which cards are folded are saved with the account list, so they
come back the way you left them after a reload or a restart.
What a refresh actually loads
Collapsed cards are skipped. Refresh all, the auto-refresh timer and the
load that happens when you open the view all read only the accounts whose cards
are open, so a login you have folded away never launches a browser. Opening a
card loads that account there and then; if its numbers are less than a minute
old they are reused rather than re-fetched, so folding and unfolding does not
cost a browser launch. A card's own Refresh button always reloads it.
Budget pace bar
Every usage window is drawn on the same bar: one segment per unit of time in the
window. The fill is what you have actually consumed, the separators are the time
milestones, and the bright marker is where consumption should have reached by
now.
Weekly (and other multi-day) windows are cut by day:
Weekly 16% ±0%
Budget pace: 5% extra
[####|####|###| | | | ]
7d 6d 5d 4d 3d 2d 1d 0d
The 5-hour session window is cut by hour, on identical maths:
Current session (5h) 4% ▲4%
Budget pace: 76% extra
[#| | | | ]
5h 4h 3h 2h 1h 0h
Fill short of the marker means allowance in hand; fill past it means you are
burning faster than the window refills. The verdict line says so in one phrase:
| Verdict |
Meaning |
5% extra |
5 points more allowance left than an even pace calls for |
on pace |
within a point of the target |
2% over |
2 points behind an even pace |
CRITICAL |
5% or less left, or a fifth of the whole allowance behind pace |
Turn the segments off with usageMonitor.showPaceGuide and every window falls
back to a plain fill bar. A window whose length the provider does not state gets
that plain bar either way, since there is no pace to judge.
Commands
| Command |
ID |
| Open Dashboard (focus the view) |
usageMonitor.openDashboard |
| Refresh Usage (all accounts) |
usageMonitor.refreshUsage |
| Add Account |
usageMonitor.addAccount |
| Sign in to Claude |
usageMonitor.signInClaude |
| Sign in to Codex |
usageMonitor.signInCodex |
| Move Account to Top |
usageMonitor.moveAccountToTop |
| Rename Account |
usageMonitor.renameAccount |
| Remove Account |
usageMonitor.removeAccount |
| Clear Account Session |
usageMonitor.clearSession |
| Clear Browser Cache (keeps sign-ins) |
usageMonitor.cleanBrowserData |
Settings
usageMonitor.autoRefreshMinutes (default 0 = manual): refresh interval
while the view is visible.
usageMonitor.browserChannel (auto | chrome | msedge): which installed
browser the controlled window uses. auto tries Chrome, then Edge.
usageMonitor.captureTimeoutSeconds (default 30): how long to wait for a
provider's usage data before reporting a failure.
usageMonitor.responseSettleSeconds (default 2): grace period for a
follow-up usage response after the first one. Skipped automatically when the
first response already contains usable data.
usageMonitor.silentRefresh (default true): refresh in an off-screen window
that closes itself, so nothing appears on your desktop.
usageMonitor.keepBrowserWarmSeconds (default 0): keep the hidden refresh
browser alive this long after a read so the next refresh skips the browser
launch. Costs a resident browser process for that window.
usageMonitor.showPaceGuide (default true): draw every usage window as a
segmented budget pace bar — by hour for the session window, by day for weekly
ones. Turn off for plain fill bars.
usageMonitor.browserCacheLimitMB (default 150): ceiling for each browser
profile's page-load caches. See Disk use below. -1 disables pruning.
Disk use
Each account's login lives in its own Chrome profile under the extension's
global storage. The login itself is small — cookies, local storage and
preferences come to a few hundred kilobytes — but Chrome surrounds it with
caches that grow on every launch. The worst offender is BrowserMetrics, which
gains a multi-megabyte spool file each time the browser starts and never
reclaims it, because the browser is closed programmatically rather than shut
down by a user. Left alone this reaches gigabytes.
The extension keeps it in check before every launch, the one moment the files
are not held open:
- always cleared: the metrics spool, crash dumps, downloaded components and
on-device models, and shader caches — none of it ever speeds up a refresh
- cleared past the cap: the HTTP and V8 code caches, which do speed up page
loads, so they are kept until their combined size exceeds
usageMonitor.browserCacheLimitMB
Sign-ins are never touched by either. Usage Monitor: Clear Browser Cache
runs a full clean on demand and reports how much it freed.
Architecture
src/
extension.ts activation, view + command wiring, status bar, output channel
types.ts shared usage/result types (windows[] model + UI states)
session/browserSession.ts Playwright persistent-context manager (per account)
session/profileMaintenance.ts browser-profile cache pruning (never touches logins)
providers/
provider.ts UsageProvider interface + context
baseProvider.ts capture→parse template + error→status mapping
parseHelpers.ts defensive JSON→window helpers
claudeProvider.ts Claude adapter (claude.ai usage capture)
codexProvider.ts Codex adapter (backend-api/wham/usage capture)
accountManager.ts account list persistence + provider instances
webview/usageViewProvider.ts WebviewView sidebar + message bridge + streaming refresh
media/
activity-icon.svg activity-bar icon
dashboard.css / .js webview styles + renderer (CSP-safe)
paceMath.js pure budget-pace maths (shared with npm test)
Provider logic is isolated behind UsageProvider so Claude and Codex evolve
independently. Each adapter maps every failure onto a typed status the sidebar
renders as a distinct state. One UsageProvider instance exists per account,
and its browser profile lives under the account id, so accounts never share a
session.
Known limitations / honesty notes
- Usage window labels: neither provider exposes a clean calendar "day". They
expose rolling windows (a ~5-hour session window and a 7-day weekly window), so
the cards show those real windows rather than inventing a daily number.
- Undocumented payloads: the usage JSON shapes are internal and change-prone.
The parsers are defensive and report Layout changed (not zero) when a shape
is unrecognized. If you hit that, the raw response is logged to the Usage
Monitor output channel so the field mapping in
claudeProvider.ts / codexProvider.ts can be tightened against a real sample.
- The window is visible by design: a real, user-driven browser is what gets
past Cloudflare; headless/automated clicking gets challenged. You can minimize
the window between refreshes.
Develop
npm install
npm run compile # or: npm run watch
npm run lint
npm test # fixture checks for the provider parsers + pace maths
Press F5 (the "Run Extension" launch config) to open an Extension Development
Host, then open the Usage Monitor view.
Package
npm run package # writes dist/usage-monitor.vsix via @vscode/vsce
Requires Google Chrome or Microsoft Edge installed on the machine (reused by the
controlled browser; no browser binaries are bundled or downloaded).