Model Analytics provides detailed insights into how different Claude models are used, including token consumption patterns and cost breakdowns.
Model Usage Distribution
A pie chart visualization shows the proportion of tokens used by each model.
Implementation
From src/components/model-breakdown.tsx:30, the component aggregates token data:
export function ModelBreakdown({ stats }: { stats: StatsCache | null }) {
const pieData = Object.entries(stats.modelUsage).map(([model, usage]) => ({
name: formatModelName(model),
value: usage.outputTokens + usage.inputTokens,
}));
}
Model identifiers are transformed into readable names:
function formatModelName(name: string): string {
return name
.replace("claude-", "") // Remove "claude-" prefix
.replace(/-\d{8}$/, "") // Remove date suffix
.replace(/-(\d+)-(\d+)$/, " $1.$2") // Convert version numbers
.replace(/-/g, " ") // Replace hyphens with spaces
.replace(/\b\w/g, (c) => c.toUpperCase()); // Capitalize words
}
Examples:
claude-4.5-sonnet-20250514 → “4.5 Sonnet”
claude-opus-3.0 → “Opus 3.0”
Color Scheme
The pie chart uses a grayscale palette:
const COLORS = ["#ffffff", "#d1d5db", "#9ca3af", "#6b7280", "#e5e7eb"];
Chart Configuration
The pie chart features:
- Inner radius of 60px (donut style)
- Outer radius of 100px
- Labels for each model segment
- Dark-themed tooltip with formatted token counts
Output Tokens by Model
A stacked bar chart compares input vs. output tokens across models.
Data Structure
The chart includes all token types:
const barData = Object.entries(stats.modelUsage).map(([model, usage]) => ({
name: formatModelName(model),
input: usage.inputTokens,
output: usage.outputTokens,
cacheRead: usage.cacheReadInputTokens,
cacheCreate: usage.cacheCreationInputTokens,
}));
Visualization
Two bars are displayed per model:
- Output tokens: White (
#ffffff) bars
- Input tokens: Gray (
#9ca3af) bars
Both use rounded corners (radius={[4, 4, 0, 0]}) for a modern appearance.
Token Details Table
A comprehensive table breaks down all token types and costs.
Columns
The table displays:
- Model: Formatted model name
- Input: Standard input tokens
- Output: Generated output tokens
- Cache Read: Tokens read from prompt cache (cost savings)
- Cache Create: Tokens written to prompt cache
- Cost: Total USD cost for this model
- Web Searches: (optional) Number of web search requests
From src/components/model-breakdown.tsx:132:
<table className="w-full text-sm">
<thead>
<tr className="border-b text-left text-muted-foreground">
<th className="pb-3 pr-4">Model</th>
<th className="pb-3 pr-4 text-right">Input</th>
<th className="pb-3 pr-4 text-right">Output</th>
<th className="pb-3 pr-4 text-right">Cache Read</th>
<th className="pb-3 pr-4 text-right">Cache Create</th>
<th className="pb-3 pr-4 text-right">Cost</th>
{hasWebSearches && <th className="pb-3 text-right">Web Searches</th>}
</tr>
</thead>
</table>
Tokens are formatted with the formatTokens utility from src/lib/utils.ts:8:
export function formatTokens(n: number): string {
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
return String(n);
}
Costs use the formatCost utility:
export function formatCost(usd: number): string {
return `$${usd.toFixed(2)}`;
}
Total Row
The table includes a totals row summing all metrics:
<tr className="border-t font-medium">
<td className="pt-3 pr-4">Total</td>
<td className="pt-3 pr-4 text-right font-mono text-xs">
{formatTokens(tokenTable.reduce((a, r) => a + r.input, 0))}
</td>
<td className="pt-3 pr-4 text-right font-mono text-xs">
{formatTokens(tokenTable.reduce((a, r) => a + r.output, 0))}
</td>
{/* ... more columns */}
</tr>
Daily Token Usage Chart
Tracks token consumption over time with model-level granularity.
Implementation
From src/components/daily-tokens-chart.tsx:27:
export function DailyTokensChart({ stats }: { stats: StatsCache | null }) {
if (!stats?.dailyModelTokens?.length) return null;
const models = new Set<string>();
for (const day of stats.dailyModelTokens) {
for (const model of Object.keys(day.tokensByModel)) {
models.add(model);
}
}
const chartData = stats.dailyModelTokens.map((day) => {
const entry: Record<string, string | number> = {
date: day.date.slice(5), // Show MM-DD only
};
for (const model of modelList) {
entry[model] = day.tokensByModel[model] ?? 0;
}
return entry;
});
}
Chart Type
The component uses a stacked area chart to show cumulative token usage:
<AreaChart data={chartData}>
{modelList.map((model, i) => (
<Area
key={model}
type="monotone"
dataKey={model}
stackId="1"
stroke={AREA_COLORS[i % AREA_COLORS.length]}
fill={AREA_COLORS[i % AREA_COLORS.length]}
fillOpacity={0.3}
name={model}
/>
))}
</AreaChart>
Data Source
Daily token data comes from the DailyModelTokens type (src/lib/types.ts:43):
export interface DailyModelTokens {
date: string;
tokensByModel: Record<string, number>;
}
Model Usage Data Structure
All model analytics consume the ModelUsage interface from src/lib/types.ts:48:
export interface ModelUsage {
inputTokens: number;
outputTokens: number;
cacheReadInputTokens: number;
cacheCreationInputTokens: number;
webSearchRequests: number;
costUSD?: number;
contextWindow?: number;
maxOutputTokens?: number;
}
Cache read tokens are significantly cheaper than standard input tokens. The cache system can reduce costs by up to 90% for repeated context.
Layout Organization
The Model Analytics view is organized in a responsive grid:
<div className="space-y-6">
<div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
<Card>{/* Model Usage Distribution Pie Chart */}</Card>
<Card>{/* Output Tokens by Model Bar Chart */}</Card>
</div>
<Card>{/* Token Details Table */}</Card>
</div>
On large screens, charts appear side-by-side. On mobile, they stack vertically.
Accessing Model Analytics
Model analytics are available in the “Models” tab of the main dashboard:
<TabsContent value="models" className="mt-6 space-y-6">
<DailyTokensChart stats={data.stats} />
<ModelBreakdown stats={data.stats} />
</TabsContent>