Analyze Claude Code API costs and token usage across sessions
Analyzes Claude Code API costs and token usage across sessions to understand spending patterns and optimize usage.
/plugin marketplace add melodic-software/claude-code-plugins/plugin install claude-code-observability@melodic-software[--days N] [--project] [--breakdown] [--export FILE]Analyze Claude Code API costs and token usage across sessions to understand spending patterns and optimize usage.
| Argument | Description |
|---|---|
--days N | Analyze last N days (default: 30) |
--project | Current project only |
--breakdown | Detailed breakdown by model, session, day |
--export FILE | Export analysis to CSV or markdown |
--compare | Compare periods (this month vs last month) |
| (no args) | Summary of recent costs |
Cost analysis uses multiple sources:
| Source | Data |
|---|---|
/cost command output | Current session costs |
| Session transcripts | Message counts, approximate tokens |
| Model inference | Input/output token estimation |
Note: Exact costs require API billing data. This command provides estimates based on message content and model pricing.
| Model | Input (per 1M tokens) | Output (per 1M tokens) |
|---|---|---|
| Claude Opus 4 | $15.00 | $75.00 |
| Claude Sonnet 4 | $3.00 | $15.00 |
| Claude Haiku | $0.25 | $1.25 |
Note: Prices may change. Verify current pricing at anthropic.com/pricing.
import json
from pathlib import Path
from datetime import datetime, timezone, timedelta
claude_dir = Path.home() / ".claude"
projects_dir = claude_dir / "projects"
def collect_session_data(days=30, project_only=False):
"""Collect token usage data from sessions."""
cutoff = datetime.now(timezone.utc) - timedelta(days=days)
sessions = []
search_dirs = [projects_dir]
if project_only:
# Limit to current project
current = Path.cwd()
project_encoded = str(current).replace(":", "").replace("/", "-").replace("\\", "-")
search_dirs = [projects_dir / project_encoded]
for project_dir in projects_dir.iterdir():
if not project_dir.is_dir():
continue
for session_file in project_dir.glob("*.jsonl"):
mtime = datetime.fromtimestamp(session_file.stat().st_mtime, tz=timezone.utc)
if mtime < cutoff:
continue
session_data = analyze_session_costs(session_file)
session_data["project"] = project_dir.name
session_data["modified"] = mtime
sessions.append(session_data)
return sessions
def analyze_session_costs(session_path):
"""Estimate costs for a single session."""
data = {
"path": session_path,
"user_messages": 0,
"assistant_messages": 0,
"agent_calls": 0,
"input_tokens_est": 0,
"output_tokens_est": 0,
"model": "sonnet" # Default assumption
}
with open(session_path) as f:
for line in f:
try:
record = json.loads(line)
record_type = record.get("type", "")
if record_type == "user":
content = record.get("message", {}).get("content", "")
data["user_messages"] += 1
# Rough estimate: 4 chars ≈ 1 token
data["input_tokens_est"] += len(content) // 4
elif record_type == "assistant":
content = record.get("message", {}).get("content", "")
data["assistant_messages"] += 1
data["output_tokens_est"] += len(content) // 4
except json.JSONDecodeError:
continue
# Calculate estimated cost
data["cost_est"] = estimate_cost(
data["input_tokens_est"],
data["output_tokens_est"],
data["model"]
)
return data
def estimate_cost(input_tokens, output_tokens, model="sonnet"):
"""Estimate cost based on token counts and model."""
pricing = {
"opus": {"input": 15.0, "output": 75.0},
"sonnet": {"input": 3.0, "output": 15.0},
"haiku": {"input": 0.25, "output": 1.25}
}
rates = pricing.get(model, pricing["sonnet"])
input_cost = (input_tokens / 1_000_000) * rates["input"]
output_cost = (output_tokens / 1_000_000) * rates["output"]
return input_cost + output_cost
def generate_cost_report(sessions, days):
"""Generate cost analysis report."""
total_input = sum(s["input_tokens_est"] for s in sessions)
total_output = sum(s["output_tokens_est"] for s in sessions)
total_cost = sum(s["cost_est"] for s in sessions)
# Group by project
by_project = {}
for s in sessions:
proj = s["project"]
if proj not in by_project:
by_project[proj] = {"sessions": 0, "cost": 0}
by_project[proj]["sessions"] += 1
by_project[proj]["cost"] += s["cost_est"]
# Group by day
by_day = {}
for s in sessions:
day = s["modified"].strftime("%Y-%m-%d")
if day not in by_day:
by_day[day] = 0
by_day[day] += s["cost_est"]
return {
"total_sessions": len(sessions),
"total_input_tokens": total_input,
"total_output_tokens": total_output,
"total_cost_est": total_cost,
"by_project": by_project,
"by_day": by_day,
"avg_per_session": total_cost / len(sessions) if sessions else 0,
"avg_per_day": total_cost / days
}
# Claude Code Cost Analysis
**Period:** 2025-12-01 to 2025-12-30 (30 days)
**Sessions Analyzed:** 156
## Cost Summary
| Metric | Value |
|--------|-------|
| **Estimated Total Cost** | $23.45 |
| **Input Tokens** | ~2.1M |
| **Output Tokens** | ~890K |
| **Average per Session** | $0.15 |
| **Average per Day** | $0.78 |
## Cost by Project
| Project | Sessions | Est. Cost | % of Total |
|---------|----------|-----------|------------|
| claude-plugins | 45 | $12.30 | 52% |
| web-app | 38 | $6.20 | 26% |
| api-server | 29 | $3.45 | 15% |
| Other (5 projects) | 44 | $1.50 | 7% |
## Daily Trend (Last 7 Days)
| Date | Est. Cost | Sessions |
|------|-----------|----------|
| 2025-12-30 | $1.23 | 8 |
| 2025-12-29 | $0.95 | 6 |
| 2025-12-28 | $0.45 | 3 |
| 2025-12-27 | $1.10 | 7 |
| 2025-12-26 | $0.80 | 5 |
| 2025-12-25 | $0.30 | 2 |
| 2025-12-24 | $0.65 | 4 |
## Model Distribution (Estimated)
| Model | Sessions | Est. Cost |
|-------|----------|-----------|
| Sonnet | 140 | $18.50 |
| Opus | 10 | $4.20 |
| Haiku (agents) | 45 | $0.75 |
## Optimization Opportunities
### High-Cost Sessions
These sessions had unusually high token usage:
| Session | Project | Est. Cost | Reason |
|---------|---------|-----------|--------|
| abc123 | claude-plugins | $2.10 | Large codebase exploration |
| def456 | web-app | $1.45 | Extended debugging session |
**Recommendations:**
- Use subagents for exploration (isolates context)
- `/clear` between distinct tasks
- `/compact` when context grows large
### Cost Reduction Tips
1. **Use Haiku for simple tasks** - 12x cheaper than Sonnet
2. **Parallelize with subagents** - Isolated context, often cheaper
3. **Clear between tasks** - Fresh context uses fewer tokens
4. **Be specific in prompts** - Reduces back-and-forth
## Quick Actions
- Detailed breakdown: `/user-config:costs --breakdown`
- Export data: `/user-config:costs --export costs.csv`
- Compare months: `/user-config:costs --compare`
--breakdown)# Detailed Cost Breakdown
## By Session (Top 20 by Cost)
| Session | Project | Date | Input | Output | Est. Cost |
|---------|---------|------|-------|--------|-----------|
| abc123 | claude-plugins | 12-30 | 450K | 180K | $2.10 |
| def456 | web-app | 12-29 | 310K | 125K | $1.45 |
| ... | ... | ... | ... | ... | ... |
## Hourly Distribution
| Hour | Sessions | Est. Cost |
|------|----------|-----------|
| 09:00 | 12 | $2.30 |
| 10:00 | 18 | $3.50 |
| 14:00 | 22 | $4.10 |
| 15:00 | 15 | $2.80 |
## Token Efficiency
| Metric | Value |
|--------|-------|
| Avg input tokens/session | 13,500 |
| Avg output tokens/session | 5,700 |
| Input:Output ratio | 2.4:1 |
/cost - Current session cost (built-in)/user-config:session-stats - Session statistics/user-config:storage - Storage usageThis command uses the user-config-management skill for: