Skip to main content

Overview

Codex-LB tracks real-time usage metrics for each account in your pool, including:
  • Rate limit consumption - Percentage of 5-minute sliding window used
  • Quota consumption - Percentage of weekly/monthly allocation used
  • Token counts - Input and output tokens per request
  • Credit balances - Available ChatGPT credits for Plus/Pro accounts
  • 28-day trends - Historical usage patterns for capacity planning

How Usage Tracking Works

Automatic Refresh

Codex-LB automatically refreshes usage data from ChatGPT’s backend API:
Default refresh interval: 300 seconds (5 minutes)
Usage refresh happens automatically during account selection. No separate background job is required.

Usage Windows

ChatGPT enforces two types of usage windows: Primary Window (Rate Limiting):
  • Duration: 5 minutes (sliding window)
  • Limit: Varies by plan (e.g., 80 requests per 5 minutes for Plus)
  • Reset behavior: Continuous sliding - older requests expire rolling off
Secondary Window (Quota):
  • Duration: 7 days (weekly) or 30 days (monthly)
  • Limit: Varies by plan (e.g., 10M tokens/week for Plus)
  • Reset behavior: Hard reset at fixed interval

Data Model

Usage data is stored in the usage_history table:
Each refresh creates new rows with current snapshots. Historical data enables trend analysis.

Usage in Load Balancing

The load balancer uses usage data to make routing decisions:
Usage-weighted routing prioritizes accounts with lower used_percent:
Accounts are sorted by:
  1. Secondary usage % (quota window) - lowest first
  2. Primary usage % (rate limit window) - lowest first
  3. Last selection time - oldest first
  4. Account ID - for stable ordering

Quota Application

The system applies quota logic to determine account availability:
Precedence rules:
  1. Monthly/weekly quota exhaustion → QUOTA_EXCEEDED
  2. 5-minute rate limit exhaustion → RATE_LIMITED
  3. Otherwise → ACTIVE
If secondary usage reaches 100%, the account is marked QUOTA_EXCEEDED regardless of primary window availability. This ensures monthly quota is respected.

Credit Tracking

For Plus and Pro accounts with credit-based billing:
Credit information is stored alongside usage percentages for monitoring and alerting.

Usage API

Get Current Usage

Response:
Response:
Trend parameters:
  • bucket_seconds: Aggregation interval (default: 21600 = 6 hours)
  • since: Start time for historical data (default: 28 days ago)
  • window: Filter by “primary” or “secondary” (default: both)
  • account_id: Filter to specific account (default: all)

Trend Calculation

From app/modules/usage/repository.py:115-167:
Each bucket contains:
  • Average usage % across all samples in that time window
  • Sample count for data quality assessment
  • Per-account, per-window granularity
Use 6-hour buckets (21600s) for 28-day overviews, or 1-hour buckets (3600s) for detailed recent analysis.

Dashboard Visualization

The web dashboard displays usage data in multiple views:

Overview Cards

  • Active Accounts: Count of accounts in ACTIVE status
  • Average Usage: Mean used_percent across all active accounts
  • Accounts Near Limit: Count where used_percent > 80%

Account Table

Columns:
  • Email
  • Status (with color coding)
  • Plan Type
  • Usage % (primary window)
  • Quota % (secondary window)
  • Reset time (relative, e.g., “in 4 hours”)
  • X-axis: Time (6-hour buckets over 28 days)
  • Y-axis: Average usage percentage
  • Lines: One per account, colored by status
  • Shading: Highlighted regions where usage exceeded 80%

Configuration

Environment Variables

Disabling Usage Tracking

To disable usage tracking entirely:
Effects:
  • Usage-weighted routing falls back to round-robin behavior
  • Dashboard shows stale usage data
  • No new usage_history rows created
  • Reduces API calls to ChatGPT backend
Disabling usage tracking disables quota-aware load balancing. Only disable if using round-robin strategy or for testing.

Performance Considerations

Database Growth

With default settings:
  • Refresh interval: 300 seconds (5 minutes)
  • Rows per account per day: 288 (24 hours × 12 refreshes/hour)
  • Retention period: 28 days
  • Total rows for 10 accounts: ~80,000 rows
Storage:
  • Each row: ~200 bytes
  • 80,000 rows: ~16 MB
Regular cleanup via retention policy keeps database size manageable.

API Call Overhead

  • Calls per refresh: 1 per account
  • Calls per day: (86400 / interval) × account_count
  • Example (10 accounts, 5-min interval): 10 × 288 = 2,880 calls/day
ChatGPT’s usage API has generous limits and these calls do not count toward request quotas.

Query Performance

Indexes optimize common queries:
Typical query times:
  • Latest usage by account: Less than 10ms
  • 28-day trend aggregation: Less than 100ms
  • Full usage export: Less than 500ms

Troubleshooting

Stale Usage Data

Symptom: Usage percentages not updating Causes:
  • USAGE_REFRESH_ENABLED=false
  • All accounts deactivated (no refresh triggers)
  • ChatGPT API returning errors (check logs)
Solution: Check settings and logs, ensure at least one active account

Missing Usage History

Symptom: Trends chart empty or incomplete Causes:
  • Recently added accounts (no historical data yet)
  • Database cleared or reset
  • Retention policy deleted old data
Solution: Wait for refresh cycles to populate data (5 minutes per data point)

Usage Not Reflecting Reality

Symptom: Dashboard shows low usage but requests failing Causes:
  • Cached data (5-minute refresh lag)
  • Primary vs secondary window confusion
  • Multiple Codex-LB instances not sharing state
Solution:
  1. Wait for next refresh cycle
  2. Check which window (primary/secondary) is exhausted
  3. Ensure single Codex-LB instance or shared database

Technical Reference

Key source files:
  • app/modules/usage/updater.py - Usage refresh logic
  • app/modules/usage/repository.py - Usage data queries
  • app/core/usage/quota.py - Quota application rules
  • app/core/usage/types.py - Type definitions
  • app/db/models.py:62-77 - UsageHistory model