How to Monitor Claude API Token Costs
If you're running Claude in production, token costs can swing wildly between a quiet week and a traffic spike, a prompt change, or a new feature that quietly doubles your context length. Monitoring Claude API token costs means tracking input and output tokens per request, aggregating them by user or feature, and comparing that against your pricing tier in near real time — not just checking the invoice at the end of the month.
The short answer: every Claude API response includes a usage object with input_tokens and output_tokens. Capture that on every call, store it with metadata (endpoint, model, user ID, feature), and roll it up into dashboards or alerts. Below is how to do that properly, what to watch for, and where it tends to go wrong.
Why token costs drift without warning
Token costs rarely spike because of one obvious thing. More often it's a combination of small changes:
- A system prompt grew from 200 to 1,200 tokens after someone added "helpful" instructions.
- A RAG pipeline started retrieving more chunks than intended.
- Conversation history isn't being trimmed, so turn 20 of a chat sends the full transcript every time.
- A retry loop silently reissues the same expensive call three times on transient errors.
- You switched models (e.g., for better quality) without re-checking the per-token price.
None of these show up until you're looking at actual per-request token counts, not estimates.
Step 1: Capture usage data on every request
Every Claude Messages API response returns usage metadata alongside the completion:
{
"id": "msg_01...",
"model": "claude-...",
"usage": {
"input_tokens": 512,
"output_tokens": 184
}
}
Log this for every single call — success or failure, since failed-but-billed calls (e.g., a response cut off by a rate limit after tokens were generated) still matter. A minimal logging wrapper looks like this:
async function callClaude(payload, meta) {
const res = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"x-api-key": process.env.ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify(payload),
});
const data = await res.json();
await logUsage({
userId: meta.userId,
feature: meta.feature,
model: payload.model,
inputTokens: data.usage?.input_tokens ?? 0,
outputTokens: data.usage?.output_tokens ?? 0,
timestamp: Date.now(),
});
return data;
}
The key fields to log consistently: model name, input tokens, output tokens, which feature or endpoint triggered the call, and a user or account identifier. Without that last piece, you can see total spend but not who is driving it.
Step 2: Convert tokens into cost at the point of logging
Don't wait until the end of the pipeline to compute dollar cost — do it right after logging, using the current price per model. Keep a small lookup table in your codebase or config, since Anthropic's per-model pricing differs for input vs. output tokens:
const PRICING = {
"claude-opus-4": { input: 15.00, output: 75.00 }, // per million tokens
"claude-sonnet-4": { input: 3.00, output: 15.00 },
};
function estimateCost(model, inputTokens, outputTokens) {
const rate = PRICING[model];
return (
(inputTokens / 1_000_000) * rate.input +
(outputTokens / 1_000_000) * rate.output
);
}
Store the computed cost alongside the raw token counts so you can re-aggregate by day, user, or feature without recomputing from scratch every time pricing changes.
Step 3: Aggregate and watch the right metrics
Raw per-request logs are useful for debugging, but for monitoring you want rollups. At minimum, track:
- Daily spend per model — catches sudden shifts from a model change or fallback logic.
- Average tokens per request, by feature — catches prompt bloat before it becomes expensive.
- Top users/accounts by token spend — useful for usage-based pricing and abuse detection.
- Output-to-input token ratio — a rising ratio often means verbose responses or missing
max_tokenscaps.
A simple SQL query against a logs table gets you most of the way:
SELECT
DATE(timestamp) AS day,
model,
SUM(input_tokens) AS total_input,
SUM(output_tokens) AS total_output,
SUM(cost) AS total_cost
FROM claude_usage_logs
GROUP BY day, model
ORDER BY day DESC;
Run this daily and plot it. Even a basic spreadsheet beats waiting for the monthly bill.
Step 4: Set thresholds, not just dashboards
Dashboards tell you what happened. Thresholds tell you something's wrong now. Decide ahead of time what "unusual" looks like for your app — e.g., daily spend 2x the 7-day average, or a single user account exceeding 500K tokens/day — and page or Slack-notify when it's crossed. This is cheap to build on top of the logging table you already have.
Where SubToAPI fits in
If you're exposing Claude through your own product rather than calling it directly from internal services, SubToAPI adds per-key usage metadata on top of your existing Claude access — so each sub_live_... key used by a customer or team shows its own token and request history without you building that logging layer yourself. It's useful when you need to monitor costs per application or per customer, not just in aggregate. See the docs or quickstart for how usage data is returned on each call, and pricing for plan details if you're deciding between Solo, Team, and Scale seats.
Whether you build your own logging pipeline or use a layer like this, the principle is the same: capture token usage at the source, attach context to it, and aggregate often enough to catch drift before it shows up as a surprise invoice.
FAQ
Does the Claude API report token usage automatically? Yes — every Messages API response includes a usage object with input_tokens and output_tokens. You don't need to count tokens yourself; just log what's returned.
How often should I check token costs? Daily aggregation is enough for most teams, but set automated threshold alerts so you're notified immediately if spend spikes, rather than discovering it during a weekly review.
Can I monitor costs per user or per feature, not just overall? Yes, as long as you attach metadata (user ID, feature name) to each logged request. Without that tag, you'll only see total spend, not where it's coming from.