CostCompass An Almanac Beta
Claude cache dashboard

Your prompt cache leaves its verdict on one screen

The Claude Console has a Caching page that answers the questions you would otherwise add logging to answer: is the cache reading, is it paying back the write premium, and when a read breaks, which part of the request changed. This guide reads that screen as a three-question diagnosis — no instrumentation required.

By Joubert Berger Updated July 9, 2026

Prompt caching fails silently. I know because I broke one on purpose for this guide: twelve requests, each paying to re-write a 19,000-token prefix it should have been reading back, and not one of them raised an error. If that were your production traffic, the usual next move would be to instrument — log the usage block on every response, ship it, wait for enough data to tell you whether the cache is doing anything. You don’t have to. The Claude Console already collected those counters and drew them for you, on one page most people never open.

This guide reads that page. It is the Console companion to Prompt Caching Explained (the economics), How to Enable Prompt Caching (turning it on), and Why Your Prompt Cache Isn’t Working (the code-and-counters method, any provider). This one is Anthropic-only and about diagnosing by looking instead of instrumenting; where the mechanics or the math matter, it links back.

The screen is at platform.claude.com/usage/cache (Analytics → Caching in the Console). Everything below was observed there on July 8, 2026; the labels and numbers are dated because a vendor UI drifts, so re-check the tooltips against what you see.

One screen, three questions

Diagnosing a prompt cache reduces to three questions asked in order — did it read, did it pay, and, when a read broke, which segment changed (the troubleshooting guide derives them from the response counters). Each question has one home on this page.

  • Did it read? The Cache read ratio tile and the Input token composition chart.
  • Did it pay? The Write amort. column — short for write amortization — in the Cache usage breakdown table (and its own trend chart).
  • Which segment broke? The Cache diagnostics area, backed by the Group by and Workspace controls.
The top of the Claude Console Caching page filtered to Model Claude Haiku 4.5. The controls row shows Workspace All, Model Claude Haiku 4.5, Range Last 7 days, Group by Workspace, and a 'Data as of' timestamp with an 'Updates hourly' caption. Below it three tiles read: Uncached input tokens 202, Cache read tokens 159K, and Cache read ratio 99.9 percent.
Figure 1. The top of the Caching page for a healthy run, filtered to one model. The Cache read ratio tile — here 99.9% — answers "did it read?" at a glance. The other two questions, did it pay and which segment broke, are read from the write amortization column and the Cache diagnostics area in Figures 2 and 3.

The controls along the top — Workspace, Model, Range, and Group by — scope every panel beneath them. One caption deserves early suspicion: the “Data as of …” timestamp. Mine sat five days stale while the data underneath it was moving; the limits section covers why.

Did it read?

Start with the Cache read ratio tile — and define it precisely, because the denominator is not what you would guess. The dashboard computes it as cache-read tokens divided by cache-read plus uncached tokens; cache-write tokens are left out entirely. So it is not cache reads over total input; it is “of the input that wasn’t a fresh write, how much came from cache.” A number you compute with writes in the denominator will read lower than the tile for the same traffic. The tile’s own tooltip states it only loosely — “share of input tokens served from cache” — and never names the denominator, so it is worth spelling out here.

A stable prefix pushes the ratio toward 100 percent; a read-side failure — stored but never matched — collapses it toward zero. The Input token composition chart tells the same story as a picture: mostly green cache read band when it works, a stack of cache write bands with the read band absent when it doesn’t. The Cache usage breakdown table puts the models side by side.

The Cache usage breakdown table comparing two models running the same repeated-document workload. One model shows a Cache read ratio of 99.9 percent and Write amort. of 11.0x, its Input Token Composition bar dominated by the green cache-read segment. The other model shows a Cache read ratio of 0.0 percent and Write amort. of 0.00x, its composition bar entirely cache-write with no cache-read segment. Column headers read Model, Input tokens, Input Token Composition, Read ratio, Write amort.
Figure 2. The same repeated-document workload on two models. The working run reads 99.9% of its non-write input from cache (composition bar almost all cache-read); the broken run — a per-request value drifted to the front of the prompt — reads 0.0% and re-writes the whole prefix every call. One glance separates a cache that reads from one that doesn't.

Those two rows are mine. The test script sends the same large document — a chunk of Pride and Prejudice from Project Gutenberg — twelve times against each model. On one model it goes out as a byte-stable cached prefix. On the other, a fresh timestamp and UUID get prepended to the front of every request. The stable version read 99.9 percent of its non-write input from cache; the broken one read 0.0 percent and paid to re-write the whole prefix twelve times. If your own row looks like the second one, you have localized the problem to the read side, and the next question is which part of the request drifted. If it looks like the first, the cache is reading. Whether it is saving you anything is the next question.

Did it pay?

The Write amort. column of the breakdown table tracks reads-per-write reuse: cache-read tokens divided by cache-write tokens. On Claude a cache write is billed above the normal input rate, so a stored prefix only pays off once enough reads follow it before it expires. The multiplier tracks exactly that. Comfortably above one read per write, the reuse is paying the premium back. At or near one, it isn’t. And 0.00x, on a run that never reads, is the worst case: you paid to write the prefix and got nothing for it. In the contrast above, the working model sits at 11.0x — eleven reads for every write — against the broken model’s 0.00x.

This is why the read ratio alone is not enough. A workload can post a healthy read ratio and still lose money if the writes outnumber the reads that follow them — thin reuse, entries expiring between calls, or parallel calls that all write before any of them reads. That is an economics failure, not a broken cache, and the break-even math that decides it — the write premium, the read discount, the point where reuse starts paying — belongs to Prompt Caching Explained; this guide does not re-derive it. What the screen adds is the over-time view: dedicated Write amortization and Cache read ratio trend charts, each with its own Window selector. A read ratio that drifts down, or an amortization that sags toward one, is a regression starting to show.

Which segment broke?

When the read ratio has collapsed, you know a stored prefix stopped matching. The cache compares the leading prefix byte for byte and stops at the first token that differs, so the break lives in exactly one part of the request — the model, the system prompt, the tool definitions, or the earlier message history. Eyeballing two large requests for that one difference is miserable. The Cache diagnostics area does it for you.

Diagnostics is a separate opt-in beta, and it is API-driven — there is no Console toggle. Two additions to each request turn it on: the beta header, and the prior response’s id threaded in as previous_message_id (None on the first turn).

resp = client.beta.messages.create(
    model="claude-opus-4-8",
    system=[{"type": "text", "text": SYSTEM, "cache_control": {"type": "ephemeral"}}],
    messages=messages,
    diagnostics={"previous_message_id": prev_id},   # None on the first turn
    betas=["cache-diagnosis-2026-04-07"],
    max_tokens=1024,
)
prev_id = resp.id
# resp.diagnostics.cache_miss_reason.type -> "system_changed", "model_changed", ...

The API compares each request against its predecessor and returns a cache_miss_reason naming the first divergence; until diagnosed requests exist, the Console area reads “No diagnostics data yet.” The reasons map one-to-one onto the request segments, and each points at a fix that lives in the troubleshooting guide — the screen’s job is to point at the right one. (The evidence script has the full version, including the loop that threads prev_id across turns.)

cache_miss_reasonWhat changedFix
model_changeda router or fallback picked another modelhold the model constant
system_changeda per-request value in the system promptmake the system prompt byte-stable
tools_changedtools reordered, added, or serialized non-deterministicallysend a fixed, sorted tool list
messages_changedearlier history edited instead of appendedtreat history as append-only
previous_message_not_found, unavailableno comparison was producednot a divergence — resend with the beta header, keep calls close in time
The Cache diagnostics area populated for the broken run, showing three panels. The Cache miss tokens table lists one model with 11 requests and about 224K tokens, its 'By reason' bar entirely the System changed colour. The Missed tokens by reason and Requests by miss reason time-series charts spike at the right edge in the same System changed colour; the Requests-by-reason legend also lists Full match, Messages changed, Tools changed, Model changed, Previous message not found, and Unavailable.
Figure 3. Cache diagnostics for the broken run. The only change was a value prepended to the system prompt, and every diagnosed miss is attributed to system_changed — 11 requests, roughly 224K tokens of lost prefix. The reason tells you which segment to fix.

That is exactly what my broken run reported. Its only per-call change was the timestamp prepended to the system prompt, and all eleven diagnosed misses came back system_changed — roughly 224K tokens of prefix lost. (The first call shows no reason at all; there was nothing to compare it against yet.) Diagnostics answers “did my request change”; the read counter answers “did the cache hit.” Read together they separate a changed request from an entry that simply expired — the same distinction the troubleshooting guide draws.

The controls are diagnostic levers

Two of the filters along the top do more than narrow the view; they isolate specific read-side causes.

Group by Model catches a model_changed miss. The cache is per-model, so if a router, an A/B split, or a retry path quietly selected a different model than the one that wrote the entry, nothing matches. Grouping by model shows it directly: one model carries a healthy read ratio while another running the same workload sits near zero. Without the grouping you would be chasing that through logs.

The Workspace filter catches an isolation-boundary miss. Caches are scoped to an API key, workspace, and organization, so two calls made from different workspaces cannot reuse each other’s entries even when the bytes match perfectly. If reads look healthy under one workspace and vanish under another, the boundary, not the prefix, is the problem. (The same scoping is why diagnostics only compares requests made within one workspace.)

What the screen can’t tell you

Two limits keep this from being the whole story.

First, it is Claude only, though the boundary is narrower than it looks. Only the why-it-missed diagnosis is exclusive: the request-comparison Cache diagnostics, and the cache_miss_reason that names the segment that changed, run only on the Claude API. The read and write metrics are not — Amazon Bedrock publishes CacheReadInputTokens and CacheWriteInputTokens to CloudWatch (chartable over time, with per-interaction caching metrics in the console playground), and Google Vertex exports cached-token counts to Cloud Monitoring. What neither has is a purpose-built cache page like this one, so on those providers you build the read/write view yourself, or read the counters straight from each response’s usage object, with the portable method in the troubleshooting guide.

Second, it lags, and the caption lies about it. The page updates hourly, and the usage-based panels lag further than the diagnostics panels. When I ran the tests above, the diagnostics picked them up quickly — but the tiles, the breakdown, and the “Data as of” caption sat on a five-day-old snapshot for hours afterward. I assumed I had done something wrong. I hadn’t; the usage rollup simply had not run yet, and when it did, everything appeared at once. Don’t read the caption as freshness. The reliable signal that a run has landed is the model rows you expect appearing in the Cache usage breakdown table; until they do, you are looking at stale usage even if the diagnostics already moved.

Watching it over time

Every failure on this screen is silent — the request succeeds and only a number moves. A cache you repaired today can regress next month from a change that looks unrelated: a per-request field added to the system prompt, a tool reordered in a refactor, a debug timestamp left in after an incident. The only thing that catches them is a signal you are already watching.

On Claude, the read ratio and write amortization trend charts are that signal — check that cached-token share holds near the fraction you expect and that amortization stays above one. If you call several providers, those signals sit on a different screen for each provider, which is where pulling them into one place earns its keep; tracking AI costs across providers covers that, and CostCompass pulls usage from your connected providers into one running total so cached-token share and cost-per-request are visible when you look, instead of being reconstructed from a separate dashboard each.

Next steps

The Claude Console already ran the diagnosis for you; the skill is knowing which panel answers which question. Read the read ratio, then the write amortization, then the diagnostics, and every failure lands in one place: nothing reading (read-side), reading but not paying (economics-side), or a named segment that changed.

From here:

  • Understand the economics behind the write amortization column. Prompt Caching Explained derives the write premium, read discount, and the break-even that decides whether a working cache actually saves.
  • Diagnose caches in code, on any provider. Why Your Prompt Cache Isn’t Working is the portable method behind this screen, including the per-segment fixes for each cache_miss_reason.
  • Revisit how you turned it on. How to Enable Prompt Caching has the exact per-provider markers and the verify-once procedure.
  • Watch it across providers over time. Tracking AI costs across providers covers keeping cached-token share and cost-per-request in view so a regression shows up as a moving metric.

Frequently asked questions

Where is the cache usage screen in the Claude Console?
It is the Caching page under Analytics in the Claude Console, at platform.claude.com/usage/cache. It shows three read-side signals — a Cache read ratio tile, a Cache usage breakdown table with a Write amortization column, and (once you opt in) a Cache diagnostics area — plus time-series charts for composition, read ratio, and write amortization. This is an Anthropic Console feature only; there is no equivalent unified pane on Amazon Bedrock or Google Vertex.
What does cache read ratio mean on the Claude dashboard?
It is the share of your non-write input tokens that were served from cache. The dashboard computes it as cache-read tokens divided by cache-read plus uncached tokens — it excludes cache-write tokens from the denominator, so it is not the same as cache reads over total input. A healthy, stable prefix drives it toward 100 percent (a working run measured 99.9 percent); a read-side failure collapses it toward zero. The tile's own tooltip states it only loosely — "share of input tokens served from cache" — so the denominator is worth pinning down, and the measured numbers bear out that writes are left out of it.
What is write amortization in Claude's caching screen?
Write amortization is reads-per-write reuse: cache-read tokens divided by cache-write tokens. It answers whether a stored prefix was reused enough to pay back what the write cost. A value at or below one read per write means the write premium is not being repaid; a healthy run measured 11.0x. It is a different question from read ratio — a cache can read correctly and still not save money. The break-even math behind it lives in the prompt caching economics guide.
Why is my Claude cache write high but cache read zero?
Something is being stored and then never matched — a read-side failure. On the dashboard it shows as a Cache usage breakdown row with a full cache-write band and no cache-read band, a read ratio near zero, and a write amortization of 0.00x. The cache match is a byte-exact comparison of the leading prefix, so a per-request value that has drifted toward the front of the request resets the match every call. Turn on Cache diagnostics to have the API name the segment that changed.
My Claude cache read is always 0 — how do I see why on the dashboard?
Enable Cache diagnostics. It is an API-only beta (the header cache-diagnosis-2026-04-07 plus a diagnostics.previous_message_id passed on each call); once you send diagnosed requests, the Console's Cache diagnostics area fills in and attributes each miss to a reason — model_changed, system_changed, tools_changed, or messages_changed. A controlled broken run whose only change was a value prepended to the system prompt was correctly attributed to system_changed.
Does the Claude cache dashboard update in real time?
No. The page updates hourly, and the usage-based panels lag further than the diagnostics panels — when I generated the test data for this guide, the diagnostics filled in quickly while the tiles, breakdown, and the "Data as of" caption stayed five days stale for hours before catching up. Treat the "Data as of" caption as unreliable for freshness; the real signal that a run has landed is the expected model rows appearing in the Cache usage breakdown table.
Can I see prompt cache stats for Bedrock or Vertex on this screen?
Not on this screen — the Caching page and the request-comparison Cache diagnostics are Claude-only. You are not blind on the other providers, though: Amazon Bedrock publishes CacheReadInputTokens and CacheWriteInputTokens to CloudWatch (and shows per-interaction caching metrics in the console playground), and Google Vertex exports cached-token counts to Cloud Monitoring, so you can build a read/write view there. What no other provider offers is the cache_miss_reason diagnosis that names the request segment that changed. For the raw per-response counters, the cross-provider troubleshooting guide covers reading them from each response's usage object.

About the author

Joubert Berger builds CostCompass, a spend-intelligence dashboard that pulls usage from AI and compute providers into one month-to-date total, a forecast, and a per-provider breakdown. This guide reflects how CostCompass reads each provider's own usage API — see the security model for how your keys are handled.

Watch cached-token share without stitching dashboards together

A cache regression shows up first as a read ratio that quietly drifts down. CostCompass pulls usage from your connected providers into one running total, so cached-token share and cost-per-request are there when you look instead of scattered across a separate screen per provider.