Developer Tools

I Built a Dashboard to Monitor All My Codex Accounts at Once

If you're using OpenAI Codex seriously, you've probably hit this wall: multiple accounts, each with its own 5-hour and weekly limits, and the only way to check any of them is to log in and run /status. Here's how I fixed it with a small local Python dashboard.

FN
Fahid Nadeem
May 29, 2026 · 6 min read

If you're using OpenAI Codex seriously, you've probably hit this wall: you have multiple accounts, each with its own 5-hour and weekly usage limits, and the only way to know how much any of them has left is to log into each one individually and run /status.

That gets old fast. Here's how I solved it with a small Python dashboard that shows every account's remaining limits on one page — no third-party apps, no keychain access, nothing leaving my machine.

The Problem

Codex Plus accounts come with two rolling usage windows: a 5-hour window that resets every 5 hours, and a weekly window that resets every 7 days. When you're rotating between accounts as each one hits its limit, you need to know at a glance which account has room. Logging into each one to check is exactly the kind of friction that sounds minor until you're doing it five times a day.

There's no official API for this — OpenAI doesn't expose a "check my Codex limits" endpoint in their platform API. The usage data lives inside each account's OAuth token, the same login your Codex CLI already stores locally at ~/.codex/auth.json. That's the key insight the whole thing is built on.

How It Works

When you log into Codex, it saves a login token to ~/.codex/auth.json. That token is all you need to ask OpenAI's backend how much usage is left on that account. The script reads the file, makes one HTTPS call per account, and gets back the same numbers /status shows you inside the app — no password, no keychain, no third-party service. The token is sent only to chatgpt.com and never stored or logged anywhere.

For multiple accounts, each login lives in its own isolated folder:

mkdir -p ~/.codex-acct1
CODEX_HOME=~/.codex-acct1 codex login
 
mkdir -p ~/.codex-acct2
CODEX_HOME=~/.codex-acct2 codex login

Each folder holds one account's login, completely independent of the others. The dashboard reads all of them.

The Dashboard

Every account's remaining capacity, refreshing live.

The whole thing is a single Python file, standard library only, no pip packages. It spins up a tiny local web server on localhost:8788 and serves one page that shows every account as a card — 5-hour remaining and weekly remaining, each color-coded green/amber/red with a progress bar and a reset countdown, plus any emergency limit-reset credits the account has left. The page refreshes itself every 60 seconds, with a manual Refresh button for an instant update. It binds to 127.0.0.1 only — nothing is exposed to the internet.

def fetch_one(auth_path):
    _, access, _ = _load_auth(auth_path)
    exp = _jwt_exp(access)
    if exp and exp - time.time() < 90:
        access = _refresh(auth_path) or access
    try:
        return _get_usage(access)
    except urllib.error.HTTPError as e:
        if e.code != 401:
            raise
        access = _refresh(auth_path)
        return _get_usage(access)

Keeping Logins Alive Automatically

The first version had a problem: if an account sat idle long enough, its short-lived access token would expire and the card would go stale, and I'd have to manually re-login to restore it.

The fix was to make the dashboard maintain its own logins. Each auth.json stores both a short-lived access token and a long-lived refresh token. Before every usage fetch, the script checks whether the access token is close to expiring and quietly renews it using the refresh token — the same mechanism the Codex CLI uses internally:

exp = _jwt_exp(access)
if exp and exp - time.time() < 90:
    access = _refresh(auth_path)

That means the dashboard's monitor logins stay alive on their own, completely separate from whatever accounts I'm actively working in. Set it up once and it handles itself.

The one thing it can't survive is a deliberate Log Out from the Codex app — that kills the refresh token everywhere, including the dashboard's copy. The fix is a one-line alias per account:

alias fixacct1='CODEX_HOME=~/.codex-acct1 codex login'
alias fixacct2='CODEX_HOME=~/.codex-acct2 codex login'

Add these to ~/.zshrc, and restoring a dropped account is just typing fixacct1 in Terminal.

The Team Overview

Below the account cards, two more panels answer questions the cards can't: a "pool weekly capacity" donut showing the average weekly room left across all accounts, plus which account frees up soonest; and a 7-day timeline with a dot for each account on the day its weekly limit refills. Both update on the same 60-second cycle.

Making It Easy to Use

A script you have to launch from Terminal every day gets old, so a double-click desktop launcher starts the server and opens the browser automatically. For switching between accounts day-to-day, short aliases beat typing the full CODEX_HOME command every time:

alias codex1='CODEX_HOME=~/.codex-acct1 codex'
alias codex2='CODEX_HOME=~/.codex-acct2 codex'
alias codex3='CODEX_HOME=~/.codex-acct3 codex'

Now codex2 opens a session as account 2, full stop.

The Honest Caveats

This uses an undocumented endpoint. There's no official API for Codex usage limits, so this reads from the same internal backend the CLI uses — it works well until OpenAI changes something. Occasionally Cloudflare protection tightens and blocks plain HTTP requests to chatgpt.com, which breaks the fetch temporarily; that's happened before and typically resolves within a day or two.

Tokens are real credentials. The auth.json files hold actual login tokens. Keep them out of git, don't sync them to cloud folders, and don't expose port 8788 to the internet.

Logging out breaks the slot. If you log out of an account in the Codex app rather than just switching to another, that account's token is invalidated everywhere. To avoid it, open a new session with CODEX_HOME=~/.codex-acctN codex instead of hitting Log Out inside the app.

The Result

One glance, every account's limits, all in one place. Green means plenty of room, amber means getting tight, red means switch now, and the reset countdowns tick down live so I always know exactly when each account frees up.

It's a small build — a few hundred lines of vanilla Python. But it replaced a daily routine of logging in and out of several accounts just to answer one question: which one has room right now. That's the kind of tool worth building.