iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🔔

Monitoring Claude Usage in the Menu Bar: A Single-File Implementation with SwiftBar and OAuth API

に公開

When using Claude Pro/Max, keeping track of the 5-hour session and weekly usage limits can be a hassle. Since opening claude.ai every time to check these is tedious, I decided to display them constantly in the macOS menu bar.

Recently, a weekly quota for Claude Design was added, so I decided to combine the 5-hour, weekly, and Design quotas into a single line:

5h:21% (4h14m) 7d:74% (9h24m) De:7% (Mon)

About Claude Design

Released as a research preview in April 2026, this is Anthropic's visual creation tool. It allows you to create slides, UI prototypes, one-pagers, and more through conversations with Claude. It is based on Claude Opus 4.7 and is available for Pro, Max, Team, and Enterprise plans.

Structure of Limits

Usage limits on claude.ai are managed through three independent buckets:

Bucket Reset Scope
5-hour session 5 hours after the first message (rolling) Regular conversations
Weekly (all models) Every 7 days Combined total of claude.ai and Claude Code
Weekly (Claude Design) Every 7 days Design usage only

The weekly bucket for all models is aggregated across claude.ai conversations, IDE plugins, and Claude Code. Since the Design bucket is independent, using Design does not affect your regular weekly quota.

*Note: Definitions and names of these buckets may be changed by Anthropic without notice.

Mechanics

Claude Code saves an OAuth token to the macOS Keychain upon login. By using this token to query Anthropic's internal endpoint api.anthropic.com/api/oauth/usage, you can retrieve the same usage data displayed in the claude.ai UI. This endpoint was discovered by the community while inspecting Claude Code's network traffic.

The response takes the following form. The Design quota is returned under the key seven_day_omelette.

{
  "five_hour":          { "utilization": 21.0, "resets_at": "..." },
  "seven_day":          { "utilization": 74.0, "resets_at": "..." },
  "seven_day_omelette": { "utilization":  7.0, "resets_at": "..." }
}

*Note: seven_day_omelette is the internal key name for Claude Design and is not documented in official manuals.

Prerequisites

  • Claude Code installed and logged in
  • SwiftBar installed

Script

Save the following as claude-usage.5m.sh in your designated SwiftBar plugin directory and run chmod +x on it.

#!/bin/bash
# <bitbar.title>Claude Usage</bitbar.title>
# <bitbar.version>v1.2</bitbar.version>
# <bitbar.refreshInterval>300</bitbar.refreshInterval>

CACHE_FILE="$HOME/.cache/claude-usage.json"
mkdir -p "$(dirname "$CACHE_FILE")"

CREDS=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null)
if [ -z "$CREDS" ]; then
  echo "Claude: N/A"
  exit 0
fi

TOKEN=$(echo "$CREDS" | python3 -c "
import sys, json
d = json.load(sys.stdin)
print(d.get('claudeAiOauth', {}).get('accessToken', ''))
" 2>/dev/null)

if [ -z "$TOKEN" ]; then
  echo "Claude: auth error"
  exit 0
fi

RESPONSE=$(curl -s "https://api.anthropic.com/api/oauth/usage" \
  -H "Authorization: Bearer $TOKEN" \
  -H "anthropic-beta: oauth-2025-04-20" \
  -H "Accept: application/json")

IS_OK=$(echo "$RESPONSE" | python3 -c "
import sys, json
try:
    d = json.load(sys.stdin)
    sys.exit(0 if 'error' not in d else 1)
except Exception:
    sys.exit(1)
" 2>/dev/null; echo $?)

if [ "$IS_OK" -eq 0 ]; then
  echo "$RESPONSE" > "$CACHE_FILE"
elif [ -f "$CACHE_FILE" ]; then
  RESPONSE=$(cat "$CACHE_FILE")
else
  echo "Claude: rate limited"
  exit 0
fi

echo "$RESPONSE" | python3 -c "
import sys, json, datetime

try:
    d = json.load(sys.stdin)
except Exception:
    print('Claude: error')
    sys.exit(0)

def pct(key):
    v = d.get(key)
    if v and v.get('utilization') is not None:
        return int(round(v['utilization']))
    return None

def remaining(key):
    v = d.get(key)
    if not v or not v.get('resets_at'):
        return None
    t = datetime.datetime.fromisoformat(v['resets_at'])
    now = datetime.datetime.now(datetime.timezone.utc)
    secs = int((t - now).total_seconds())
    if secs <= 0:
        return 'reset'
    h, rem = divmod(secs, 3600)
    m = rem // 60
    days, h2 = h // 24, h % 24
    if days:
        return f'{days}d{h2}h'
    elif h:
        return f'{h}h{m:02d}m'
    else:
        return f'{m}m'

def reset_day(key):
    v = d.get(key)
    if not v or not v.get('resets_at'):
        return None
    t = datetime.datetime.fromisoformat(v['resets_at'])
    return t.astimezone().strftime('%a')

fh_pct = pct('five_hour')
sd_pct = pct('seven_day')
de_pct = pct('seven_day_omelette')  # Claude Design weekly quota. Remove de_ variables and output lines if not needed

fh_rem = remaining('five_hour')
sd_rem = remaining('seven_day')
de_day = reset_day('seven_day_omelette')

fh_str = f'{fh_pct}%' if fh_pct is not None else 'N/A'
sd_str = f'{sd_pct}%' if sd_pct is not None else 'N/A'
de_str = f'{de_pct}%' if de_pct is not None else 'N/A'

fh_rem_str = f' ({fh_rem})' if fh_rem else ''
sd_rem_str = f' ({sd_rem})' if sd_rem else ''
de_day_str = f' ({de_day})' if de_day else ''

print(f'5h:{fh_str}{fh_rem_str} 7d:{sd_str}{sd_rem_str} De:{de_str}{de_day_str}')
print('---')
print(f'5h session:  {fh_str}{fh_rem_str}')
print(f'Weekly:      {sd_str}{sd_rem_str}')
print(f'Design:      {de_str}{de_day_str}')  # Remove if not needed
"

The .5m. in the filename sets the update interval to 5 minutes. If the API hits a rate limit, the script displays the last cached data.

SwiftBar Claude usage

About Rate Limits

In practice, the rate limits for /api/oauth/usage (HTTP 429) are quite aggressive, and once triggered, they may last for over 30 minutes. This is a known issue reported by multiple users on GitHub.

The script above handles this by falling back to the cached ~/.cache/claude-usage.json file if the API request fails.

Cautions

Anthropic OAuth Policy

In February 2026, Anthropic clarified in their Terms of Service that using OAuth tokens for Free/Pro/Max plans with tools other than Claude Code or claude.ai is a violation of their policy. As of April, technical blocks have been implemented against third-party tools (such as OpenClaw).

This script only retrieves usage statistics and performs no inference requests to Claude models. While the purpose differs from the subscription abuse (token arbitrage) that these restrictions target, it remains in a gray area according to the Terms of Service. Use it at your own risk.

Others

/api/oauth/usage is an internal endpoint not mentioned in official documentation. Changes by Anthropic could break this script at any time. A GitHub issue requesting an official usage API exists here, so a formal method might eventually be provided.

When running the script for the first time, macOS may display a dialog requesting permission to access the Keychain. Once you select "Allow," you will not be prompted again.

The script uses the python3 command. It runs with the default macOS Python 3, but if you manage multiple versions using Homebrew or similar, you can explicitly use /usr/bin/python3 if preferred.

GitHubで編集を提案

Discussion