--- summary: "Usage tracking surfaces and credential requirements" read_when: - You are wiring provider usage/quota surfaces - You need to explain usage tracking behavior or auth requirements title: "Usage tracking" --- ## What it is - Pulls provider usage/quota directly from each provider's usage endpoint. No estimated provider billing; only provider-reported plan names, quota windows, balances, spend, budgets, daily cost history, token/model attribution, or account-state summaries. - Human-readable quota-window output is normalized to `X% left`, even when a provider reports consumed quota, remaining quota, or only raw counts. Providers without resettable quota windows show provider summary text instead (for example a balance). - Session-level `/status` and the `session_status` tool fall back to the session's transcript log when the live session snapshot is missing token/model data. That fallback fills missing token/cache counters, can recover the active runtime model label, and prefers the larger prompt-oriented total when session metadata is missing or smaller (`totalTokensFresh !== true`, zero, or below the transcript-derived value). Nonzero live values always win over the fallback. ## Where it shows up - `/status` in chats: status card with session tokens and estimated cost (API key models only). Provider usage shows for the **current model provider** when available, as a normalized `X% left` window or provider summary text. - `/usage off|tokens|full` in chats: per-response usage footer. - `/usage cost` in chats: local cost summary aggregated from OpenClaw session logs. - CLI: `openclaw status --usage` prints a full per-provider usage/quota breakdown. - CLI: `openclaw models status` lists OAuth/token auth profiles and shows a usage-window summary next to each provider that has one. - Control UI: **Usage** shows provider plan and billing cards above OpenClaw's session-derived token and estimated-cost analysis. Anthropic and OpenAI Admin API credentials add provider-reported today, 7-day, and 30-day spend, daily trends, token totals, top models, and cost categories. - macOS menu bar: a root "Usage" section appears below Context when provider usage snapshots are available. See [Menu bar](/platforms/mac/menu-bar). `openclaw channels list` no longer prints provider usage; it points users to `openclaw status` or `openclaw models list` instead. ## Anthropic and OpenAI cost history Subscription quota and API billing are different provider surfaces: - Anthropic subscription/setup credentials continue to show Claude quota windows and optional extra-usage budgets. Set `ANTHROPIC_ADMIN_KEY` or `ANTHROPIC_ADMIN_API_KEY` to show organization Usage and Cost API history instead. An Anthropic provider credential beginning with `sk-ant-admin` is detected automatically. - OpenAI ChatGPT/Codex OAuth continues to show plan, quota windows, and credit balance. Set `OPENAI_ADMIN_KEY` to show organization cost and completions-usage history instead; optionally set `OPENAI_PROJECT_ID` to scope it to one project. OpenClaw never sends inference credentials from `OPENAI_API_KEY`, provider config, or auth profiles to organization APIs because those keys may belong to custom endpoints. Admin credentials take precedence because they provide actual organization billing. OpenClaw does not combine these provider-reported totals with its local session estimates; the two sections intentionally answer different questions. ## Default usage footer mode `/usage off|tokens|full` sets the footer for a session and is remembered for that session. `messages.responseUsage` seeds that mode for sessions that have not chosen one, so the footer can be on by default without typing `/usage` each time. Set one mode for every channel, or a per-channel map with a `default` fallback: ```jsonc { "messages": { "responseUsage": "tokens", // or: { "default": "off", "discord": "full" } }, } ``` Accepted values: `"off"`, `"tokens"`, `"full"`, and the legacy alias `"on"` (treated as `"tokens"`). ### Three distinct session states A session's `responseUsage` field has three representable states, each with different semantics: | State | Stored value | Effective mode | | ------------------- | ------------------------------- | --------------------------------------------------------------------- | | **Unset / inherit** | `undefined` (absent) | Falls through to `messages.responseUsage` config default, then `off`. | | **Explicit off** | `"off"` (stored) | Always off, a non-off config default cannot re-enable the footer. | | **Explicit on** | `"tokens"` or `"full"` (stored) | That mode, regardless of config default. | ### Precedence Effective mode = session override → channel config entry → `default` → `off`. An explicit `/usage off` is **persisted** as the literal value `"off"` in the session, not the same as "unset." A non-off `messages.responseUsage` default cannot turn the footer back on once the user has explicitly disabled it. ### Resetting vs. turning off - `/usage off` forces the footer off and persists that choice. A configured non-off default cannot override this. - `/usage reset` (aliases: `default`, `inherit`, `inherited`, `clear`, `unpin`) clears the session override. The session then **inherits** the effective config default (`messages.responseUsage`). If no default is configured, the footer stays off. - A full session reset (`/reset` or `/new`) or a session rollover **preserves** the explicit usage-mode preference so the user's display choice survives session rollovers. Only `/usage reset` (and its aliases) clears the override. ### Toggle behavior `/usage` with no arguments cycles: off → tokens → full → off. The starting point for the cycle is the **effective** current mode (session override falling through to the config default when unset), so the cycle always matches what the user currently sees in the footer. ### Config With no config the prior behavior holds (footer off until `/usage`). Use `/usage reset` to clear a session override and re-inherit the configured default. ## Custom `/usage full` footer `/usage tokens` always renders a plain `Usage: X in / Y out` line (plus cache and estimated-cost suffixes when available). Only `/usage full` renders the richer footer described below. `/usage full` shows a built-in compact footer with model, reasoning, fast/slow, context window, and cost when those fields are available. No template file is required for the built-in footer. `messages.usageTemplate` is only for advanced custom layouts. The value is a JSON file path (supports `~`) or an inline object, and it replaces the built-in footer when valid. A file path is watched and reloaded live on change. ```json { "messages": { "usageTemplate": "~/.openclaw/usage-footer.json" } } ``` Missing or empty templates fall back to the built-in footer quietly. Unreadable or invalid configured templates (bad JSON, or a shape with no renderable output pieces) also fall back to the built-in footer and emit an operator warning. Start custom templates from the built-in shape, then edit the parts you want to change: ```jsonc { "schema": "openclaw.usageBar.v1", "scales": { "braille": "⠐⡀⡄⡆⡇⣇⣧⣷⣿", "block": "░▏▎▍▌▋▊▉█", "shade": "░▒▓█", "moon": "🌑🌘🌗🌖🌕", "level": "▁▂▃▄▅▆▇█", "weather": ["🥶", "☁️", "🌥", "⛅️", "🌤", "☀️"], "plants": ["🪾", "🍂", "🌱", "☘️", "🍀", "🌿"], "moons6": ["🌑", "🌚", "🌘", "🌗", "🌖", "🌝"], }, "aliases": { "models": { "claude-opus-4-6": "opus46", "claude-opus-4-8": "opus48", "claude-sonnet-4-6": "sonnet46", "claude-haiku-4-5": "haiku45", "gpt-5.5": "gpt5.5", }, "reasoning": { "off": "🌑", "minimal": "🌚", "low": "🌘", "medium": "🌗", "high": "🌕", "xhigh": "🌝", }, }, "output": { "sep": "", "default": [ { "text": "{model.provider}{identity.emoji|🤖}{model.display_name|alias:models}" }, { "map": "model.is_fallback", "cases": { "true": "🔄" } }, { "map": "model.is_override", "cases": { "true": "📌" } }, { "when": "model.reasoning", "text": "{model.reasoning|alias:reasoning}" }, { "map": "state.fast_mode", "cases": { "true": "⚡️", "false": "🐌" } }, { "when": "context.max_tokens", "text": " | 📚[{context.pct_used|meter:5:braille}]{context.max_tokens|num}", }, { "when": "cost.turn_usd", "text": " 💰{cost.turn_usd|fixed:4}" }, ], "surfaces": { "discord": [ { "text": "-# -\n" }, { "text": "-# {model.provider}{identity.emoji|🤖}{model.display_name|alias:models}" }, { "map": "model.is_fallback", "cases": { "true": "🔄" } }, { "map": "model.is_override", "cases": { "true": "📌" } }, { "when": "model.reasoning", "text": "{model.reasoning|alias:reasoning}" }, { "map": "state.fast_mode", "cases": { "true": "⚡️", "false": "🐌" } }, { "when": "context.max_tokens", "text": " | 📚[{context.pct_used|meter:5:braille}]{context.max_tokens|num}", }, { "when": "cost.turn_usd", "text": " 💰{cost.turn_usd|fixed:4}" }, ], }, }, } ``` ### Shape ```jsonc { "schema": "openclaw.usageBar.v1", "scales": { "": "low-to-high glyphs" }, // string (1 glyph/char) or array "aliases": { "": { "": "