Cost dashboards and budgets
Track and control AI spend with cost dashboards by feature, model and customer, budgets and alerts, and spend reviewed as a product metric.
On this page
Why this matters
AI costs can change overnight. A prompt edit that adds a long example doubles input tokens on every request. A popular launch triples volume. A bug retries every failed call in a loop. A single customer’s integration starts sending enormous documents. The provider’s invoice will tell you about all of these, a month later, as one number.
A cost dashboard turns those surprises into decisions made the same day. It breaks spend down by feature, model, customer and outcome, sets budgets with owners, and alerts when something moves. This article covers what to track, how to build the view from data you already have, how to set budgets and alerts, and a monthly review that keeps spend tied to value.
What to track
The provider’s console shows spend by API key and model. That’s necessary but not enough: you need to know why money was spent. Track cost broken down by:
| Dimension | Question it answers |
|---|---|
| Feature | Which AI feature is driving spend? |
| Model and effort | Is the expensive configuration paying for itself? |
| Prompt version | Did a recent change raise cost per request? |
| Customer or plan | Who are the heaviest users, and are they profitable? |
| Outcome | How much spend goes to successes versus failures, retries and abandoned outputs? |
| Time | Is spend trending up, and is there an anomaly today? |
The last two are the most often missing. Cost by outcome shows how much of your bill is waste you could recover by improving quality. Cost over time, compared with a baseline, catches problems while they’re small.
Building the dashboard
You already have the data: every trace records the feature, prompt version, model, tokens and outcome, and your analytics events connect requests to customers and successes. The dashboard is an aggregation over those records:
Show text descriptionHide text description
A sequence of 5 steps.
- Traces : Tokens, model, feature, prompt version, outcome, customer
- Price : Tokens × current prices, from the model configuration
- Aggregate : By feature, model, customer, outcome and day
- Alert : Budgets and anomalies, sent to an owner
- Review : Monthly decisions on models, prompts, limits and pricing
This script does the aggregation and anomaly check over a day’s traces. In production you’d run the same logic as a query in your data warehouse or observability tool:
interface TraceRecord {
day: string;
feature: string;
model: string;
customer: string;
outcome: 'success' | 'failure';
costUsd: number;
}
/** Sums cost by any dimension of the trace records. */
function totalBy<K extends keyof TraceRecord>(records: TraceRecord[], key: K): Map<TraceRecord[K], number> {
const totals = new Map<TraceRecord[K], number>();
for (const r of records) totals.set(r[key], (totals.get(r[key]) ?? 0) + r.costUsd);
return totals;
}
/** Flags a day whose spend is more than `threshold` above the average of the previous seven days. */
function isAnomaly(dailyTotals: number[], threshold = 0.5): { anomaly: boolean; today: number; baseline: number } {
const today = dailyTotals.at(-1) ?? 0;
const previous = dailyTotals.slice(-8, -1);
const baseline = previous.reduce((a, b) => a + b, 0) / Math.max(1, previous.length);
return { anomaly: baseline > 0 && today > baseline * (1 + threshold), today, baseline };
}
// A day's traces, already priced (tokens × prices from the model configuration).
const today: TraceRecord[] = [
{ day: '2026-10-17', feature: 'reply-drafts', model: 'opus', customer: 'acme', outcome: 'success', costUsd: 41.2 },
{ day: '2026-10-17', feature: 'reply-drafts', model: 'opus', customer: 'acme', outcome: 'failure', costUsd: 9.8 },
{ day: '2026-10-17', feature: 'reply-drafts', model: 'opus', customer: 'globex', outcome: 'success', costUsd: 12.5 },
{ day: '2026-10-17', feature: 'doc-analysis', model: 'opus', customer: 'acme', outcome: 'success', costUsd: 88.0 },
{ day: '2026-10-17', feature: 'ticket-routing', model: 'haiku', customer: 'globex', outcome: 'success', costUsd: 0.9 },
];
const usd = (n: number) => `$${n.toFixed(2)}`;
for (const key of ['feature', 'customer', 'outcome'] as const) {
const lines = [...totalBy(today, key)].sort((a, b) => b[1] - a[1]).map(([name, cost]) => `${name} ${usd(cost)}`);
console.log(`By ${key}: ${lines.join(', ')}`);
}
// Previous seven days of total spend, then today.
const daily = [64, 71, 68, 70, 66, 69, 72, today.reduce((sum, r) => sum + r.costUsd, 0)];
const check = isAnomaly(daily);
// Point the alert at the biggest contributors, so whoever receives it knows where to look first.
const top = (key: 'feature' | 'customer') => [...totalBy(today, key)].sort((a, b) => b[1] - a[1])[0]?.[0];
console.log(
check.anomaly
? `ALERT: today ${usd(check.today)} vs 7-day average ${usd(check.baseline)}. Check ${top('feature')} and ${top('customer')} first.`
: `Normal: today ${usd(check.today)} vs 7-day average ${usd(check.baseline)}.`,
); The output points at where to look: a spike, with one feature and one customer accounting for most of the spend. That’s the value of breaking spend down before alerting. “Spend is up 80%” makes someone open the console; “doc-analysis spend for acme is up” makes someone open the right trace.
Price tokens with the same model configuration your code uses, so the dashboard stays correct when prices change. On this site, that’s the single model configuration every example reads from.
Budgets and alerts
Budgets turn the dashboard into control:
- A provider-level spending limit on each API key, so no bug or attack can exceed a hard ceiling. Use separate keys for production, staging and CI, each with its own limit.
- A monthly budget per feature, owned by the feature’s team, with alerts at 50%, 80% and 100% of the budget’s pace.
- Anomaly alerts on daily or hourly spend compared with a trailing baseline, as in the script, broken down by feature so the alert says where to look.
- Per-customer thresholds for B2B products, so account managers know before a customer’s usage becomes a pricing conversation.
Every alert needs an owner and a first action: who gets it, and what they check first. An alert that goes to a shared channel with no owner is a notification, not a control.
A monthly cost review
Once a month, for each AI feature, spend 30 minutes on these questions:
- What did we spend, and what did we get? Total cost, successes, cost per success, and the trend.
- Where is the waste? Spend on failures, retries and abandoned outputs. Which quality improvement would recover the most?
- Is the configuration right? Could a lower effort, a smaller model for one step, or caching (opens in a new tab) cut cost without hurting quality? What do the evals say?
- Who are the heaviest customers, and does their plan cover their usage? See pricing.
- What changed? New prompts, models, prices or features since last month, and their effect.
Record decisions with owners and dates. Over a few months, the review builds the history that makes AI spend predictable, and it gives leadership a clear story: what AI costs, what it returns, and what you’re doing about the gap.
Common mistakes
- Relying on the monthly invoice. It arrives too late and says too little. Track daily spend by feature, model, customer and outcome.
- One API key for everything. Use separate keys for production, staging and CI, each with its own spending limit.
- Alerts without breakdowns. “Spend is up” wastes time. Alert with the feature and customer driving the change.
- Hard-coding prices in the dashboard. Price tokens from the same configuration your code uses, and update it when prices change.
- No owner. Every budget and alert needs a person responsible and a first action.
Try it
Exercise
About 45 min
Design a cost dashboard for one feature
- List the fields your traces record, and add any missing from the table above (feature, model, prompt version, customer, outcome).
- Sketch the dashboard: total spend over time, cost per success, and breakdowns by model, customer and outcome.
- Set a monthly budget, alert thresholds and an anomaly rule, each with an owner and a first action.
- Run the script above on a day of your own traces, or realistic sample data, and check the alert points to the right place.
Show a hint
If your traces don’t record a customer or outcome yet, add them first. Without them, you can see that spend went up but not why, or whether it bought anything.
Show a worked solution
Example for AI-drafted replies:
- Dashboard: daily spend (stacked by model); cost per accepted draft (line); top 10 customers by spend; spend on accepted versus discarded drafts.
- Budget: $2,500 a month for reply-drafts, owned by the support-tools team lead; alerts at 50%, 80% and 100% of pace.
- Anomaly rule: daily spend more than 50% above the 7-day average; first action: check the breakdown by customer and prompt version.
- Hard limit: production key capped at $5,000 a month in the provider console; CI key at $200.
Check your understanding
Key takeaways
- Track cost by feature, model, prompt version, customer, outcome and time, not only from the invoice.
- Build the dashboard from traces you already have, priced with the same configuration your code uses.
- Set hard provider limits per key, budgets per feature and anomaly alerts with breakdowns, each with an owner.
- Hold a monthly cost review that connects spend to successes, waste and decisions.
Progress is saved in this browser and lights up the roadmap.
Related articles
- Unit economics of AI features Work out the unit economics of an AI feature, from cost per successful task and value per user to margins by plan and the levers that improve them. Level: Expert
- Tracing and observability for LLM calls Trace every LLM call in production, from what to record to linking traces with users and outcomes, reviewing traces, and monitoring cost and latency. Level: Advanced
- Abuse, misuse and rate limiting Protect AI features from abuse with rate limits, quotas, misuse detection and cost-attack defenses, and handle users who push a feature beyond its purpose. Level: Expert