⚡ Cache Header Analyzer
Analyze Cache-Control, ETag, Expires, Vary, Age — with human-readable max-age / s-maxage. Auto-detects major CDNs (Cloudflare, CloudFront, Fastly, Akamai, Vercel).
📚 Cache-Control Reference
• public: Cacheable by any cache including CDN/proxy
• private: Browser only (no shared caches)
• no-store: Never cache anywhere
• no-cache: May cache, but must revalidate every time
• max-age=N: Fresh for N seconds
• s-maxage=N: max-age applied only to shared caches (CDN)
• immutable: No revalidation even on reload — perfect for hashed assets
• stale-while-revalidate=N: Serve stale up to N seconds while revalidating in background
• stale-if-error=N: Serve stale up to N seconds on origin error
📖 What this check tells you
This check pulls Cache-Control, ETag, Last-Modified, Expires and CDN-specific headers out of the response and breaks the directives down for you. It can only tell you what you are instructing, not what actually got cached. A browser under storage pressure evicts regardless of your instructions, and a CDN may override them with its own rules.
| Item | What it means | How to fix it |
|---|---|---|
| No Cache-Control at all | Saying nothing does not mean not cached — the cache is free to guess a lifetime (heuristic caching). Where a Last-Modified exists, the common implementation treats roughly 10 % of the time since that date as fresh. For a page last edited a year ago, that is about a month of caching you never asked for. |
Be explicit on every response. Three patterns cover nearly everything: no-cache for HTML (store it, but revalidate every time), max-age=31536000, immutable for content-hashed assets, and private, no-store for responses containing personal data. Despite the confusing names, no-cache stores and no-store does not. |
| A long max-age on a mutable file | Put a one-year max-age on a fixed name like style.css and existing visitors will not see an update for a year. Worse, a cache already handed to a browser cannot be recalled from the server side: a CDN purge reaches the edge and no further. |
Use a long TTL only together with a design where the filename changes on update — a content hash in the name, such as app.4f2c1a.css, with the HTML reference rewritten. That makes immutable safe, and even a reload skips revalidation. If a long TTL is already out there, renaming the file and writing off the old one is the only recovery. |
| public on a personalised response | When a page containing a login name or cart contents carries public — or s-maxage — a shared cache stores it and serves it verbatim to the next, different visitor. Showing one user the personal data of another is the worst outcome a caching mistake can produce, and it typically surfaces right after a CDN is introduced. |
Return Cache-Control: private, no-store on authenticated responses. Vary: Cookie separates them in theory, but it creates an entry per cookie value, so caching effectively stops working and the CDN gains you nothing. Splitting anonymous and authenticated traffic by path or subdomain, and making only the former cacheable, is the more reliable design. |
What makes caching dangerous is that a mistake leaves your hands and keeps living. Fixing the configuration cannot recall instructions already distributed, which is why the rule is to start short and extend later when in doubt. Adding stale-while-revalidate lets you serve the old copy while refreshing in the background instead of making someone wait at the moment of expiry, so a short max-age costs nothing in perceived speed. With a CDN, a short max-age for browsers plus a long s-maxage for the edge, refreshed by purge, is the combination that stays manageable.