How to analyze your LLM usage file

Every LLM bill has a file behind it: the usage export your provider will hand you, row by row, model by model, day by day. Most people never open it, because a raw export is a wall of token counts with no totals and no verdicts. This guide shows where to get that file, what is actually in it, and the three patterns worth looking for once you can see it clearly — using the LLM usage analyzer on this site, which reads the file in your browser and nowhere else.

Where to export usage from

Start where the provider keeps the numbers. OpenAI exposes usage in two places: the usage page of the provider console, which summarises activity by day and model for the current billing period, and the usage API, which returns the same data as JSON — buckets of time, each holding per-model results with context tokens, generated tokens and request counts. That JSON shape is worth knowing because it is the one you can archive, diff and feed to tooling without screenshots. A habit worth starting today: pull the API response once a month and keep it. Providers keep only a limited window of history in the console; your own archive is the only complete record of what you actually spent, month by month.

Anthropic exposes usage and cost reporting through its console and its reporting APIs in the same spirit: aggregated by day and model, exportable as tabular data. Other providers vary in polish but not in kind — a CSV download from a usage or billing page, or an API endpoint returning dated rows. The generic shape is all any analysis needs: a date, a model name, input tokens, output tokens, and, when you are lucky, cached tokens, request counts and a cost column. If your provider offers several exports, take the most granular one it offers — daily by model beats monthly by project, because aggregation you do yourself can always be undone, and aggregation the provider did cannot.

What the file actually contains

A usage row is a small, dense claim: on this date, this model served this many requests, read this many input tokens — of which this many were cached — and wrote this many output tokens. Read a file with those columns and you can reconstruct almost everything about the shape of a workload: whether prompts are long or short, whether answers are verbose, whether traffic is steady or bursty, and which models do the real work. What the file deliberately does not contain is just as important: no prompt text, no completions, no user content. It is counts and names, which is why it can be handled more freely than the traffic it describes — though, as the last section argues, “more freely” is not “anywhere”.

Two columns deserve suspicion before any analysis. The first is cost: some exports carry billed cost, some carry a list-price estimate, and some carry none at all, and the file rarely labels which. Treat a cost column as the provider’s figure but verify the date range and the skipped or partial rows before trusting a total. The second is the cached-token column, which providers name in at least five different ways and sometimes fold into the input count instead of breaking it out. If input tokens look implausibly cheap or expensive for the model, the headers are the first place to look — which is why the analyzer shows you its column mapping, detected from the headers, and lets you correct it before anything is computed.

What to look for: three patterns

First, the cached-token ratio. Divide cached input by total input, per model. Workloads with any repeated structure — a system prompt, a document prefix, a fixed tool schema — should cache a large share of their input, because that prefix is identical on every call. A ratio near zero on such a workload means caching is switched off, the cache is expiring between calls, or something in the prefix changes on every request — a timestamp, a random id, a reordered field — and silently defeats it. Fixing that one number is routinely worth more than renegotiating the model, because cached input is billed at a fraction of the full rate on every major provider.

Second, the model mix. Sort models by cost, not by requests: the mix is healthy when the expensive tier’s cost share roughly matches the share of work that genuinely needs it. The drift to watch is a flagship model’s cost share rising month over month while its request share stays flat — longer prompts, longer outputs, or new traffic quietly routed to the big model by a default nobody remembers setting. Third, concentration and spikes: one API key, project or model dominating the file is a blast-radius fact as much as a cost fact, and a per-day spike — especially at a weekend or overnight, when nobody was working — is the signature of a retry loop, a runaway agent, or a leaked key being exercised. The per-day table exists to make that spike impossible to miss.

Pricing a file that carries no costs

Many exports have no cost column at all, and then the analysis has to price the file itself. The analyzer does it the transparent way: each row is priced from the LLM pricing table on this site — the verified list rates also used by the cost calculator — with the provider’s own formula: uncached input at the input rate, cached input at the cached rate where one exists, output at the output rate. Model names are matched strictly: exactly, after removing a provider prefix, or after stripping a trailing date or “latest” suffix. That strictness is the point. A looser, fuzzy match would eventually price a fine-tune as its base model or a preview as the release, and the total would gain a confidence it has not earned.

Which is why models that match nothing are listed, not guessed. Their tokens and requests still count — you can see their volume and judge whether the gap matters — but their cost is left blank, and the result is labelled with where its money came from: the file itself, computed from the table, a mix, or none. Hold any computed total to that standard when you read it: it is list-price arithmetic with no knowledge of your discounts, credits, batch rates or tiered long-context pricing, so it will not reconcile to the cent with an invoice. What it does reliably is rank: which models, which days, which patterns dominate the bill. In cost work, the ranking is usually the decision-relevant part.

Privacy, and a monthly routine

A usage file contains no prompt text, but it is still operationally sensitive: it names every model you run, your volumes by day, your growth curve and your spend — a competitive and security-relevant fingerprint of how a system is built. That is why the LLM usage analyzer parses the file locally in your browser and never uploads it. The general rule travels well beyond this one tool: the more a file summarises your infrastructure, the worse the idea of pasting it into a hosted chat or an unknown converter becomes, even when the file holds no secrets in the literal sense. Aggregates leak too, just more quietly.

Close with a routine small enough to actually happen. Once a month: export the file, analyse it, and write down four numbers — total cost and its source, the top model’s cost share, the cached-token ratio, and the largest single day. Compare them with last month’s four numbers. That five-minute diff catches the drift, the spike and the defeated cache while they are still cheap, and over a year it builds the archive no provider console will keep for you. Bills surprise people who only read bills. They rarely surprise people who read usage.

Frequently asked questions

Which export should I use — console CSV or the usage API JSON?

Either; they describe the same activity. The console CSV is the quickest to obtain and is enough for a one-off look. The API JSON is the better habit: it is complete, scriptable, archivable, and carries the per-model token fields (context, generated, cached where present, and request counts) in a stable shape. If the two disagree, check the date ranges and time zones first — console views are often shown in local time while API buckets are UTC, which shifts a day boundary and moves spend between adjacent days without changing the total.

My cached-token ratio is near zero. What breaks prompt caching?

The usual causes, in order: caching is not enabled or not offered on the route the traffic takes; the gap between calls exceeds the cache lifetime, so every entry expires before reuse; or the prompt prefix is not actually identical between calls — an injected timestamp, a per-request id, a shuffled tool list or a user-specific first message all change the prefix and miss the cache. Compare two raw requests byte by byte at the start: whatever differs first is where the cache stops matching. The fix is to move everything variable after a stable, shared prefix.

Why will the tool not estimate a price for some of my models?

Because no honest price exists in its table for that name. Fine-tunes inherit a base model’s engine but not necessarily its price, previews are often billed differently from releases, and third-party deployments follow their own contracts — guessing any of those would make the total look complete while making it wrong. The tool lists those models with their volumes instead, so you can price the slice yourself from your contract or invoice, and add it to the computed total with the source of each figure kept clear.