Why does my CDN not cache my page?
Common reasons are private or no-store in Cache-Control, a Set-Cookie header on the response, Vary: *, or no freshness information at all. The shared cache verdict names the reason.
Paste response headers, or just a Cache-Control value, and see exactly what a browser and a shared cache such as a CDN will do with the response: store it or not, how long it stays fresh, and how it is revalidated.
Loading the workbench.
You do not have to take our word that your headers stay here. Developer tools show every request a page makes, so you can watch this page work and confirm that nothing is sent. The check takes under a minute.
F12, or Cmd+Option+I on a Mac, and select the Network tab.Only two things can add a line to that log, and neither carries your headers. Submitting the feedback form sends the vote and comment you typed. Typing characters in a script the page has not displayed yet, such as Cyrillic or Greek, can make the browser fetch the matching font file, and that request names only the font.
2http never sends a request on your behalf: the request builder writes code for you to run, and the meta inspector reads source you paste instead of fetching a URL. The production site also sends a Content-Security-Policy header that tells your browser to refuse connections to anywhere except this site and the anonymous analytics endpoint.
The decoder follows the RFC 9111 rules. A response's freshness lifetime comes from the first of these that applies:
s-maxage, for shared caches only.max-age, for every cache.Expires minus Date. An invalid Expires, such as 0, means already stale.Last-Modified, for status codes that allow it.The current age is the Age header, optionally plus the time since the Date header. Lifetime minus age is how long the response has left, and stale-while-revalidate adds a grace period on top.
They are the most misunderstood directives in HTTP. no-cache does not mean do not cache: the response may be stored, but must be revalidated with the server before every reuse. no-store is the one that forbids storing it anywhere.
private keeps a response out of CDNs and shared proxies but allows the browser cache.public lets any cache store it, even a response that would normally be excluded.immutable tells the browser not to revalidate even on reload, for fingerprinted files.must-revalidate forbids serving a stale copy when the origin is unreachable.The decoder flags combinations that do not do what their author meant: no-store alongside max-age or immutable, public together with private, immutable with no-cache, a non-numeric max-age, Expires ignored because max-age is present, the HTTP/1.0 Pragma header, and Vary on User-Agent or Cookie that splits the cache into fragments.
One combination is a security failure: a response that sets a cookie but allows shared caching. A CDN could then serve one visitor's cookie to everyone, so the decoder marks it as a failure.
When a stored response goes stale, the browser asks the server whether it changed instead of downloading it again. It sends If-None-Match with the stored ETag and If-Modified-Since with the Last-Modified date. If nothing changed, the server answers 304 Not Modified with no body.
Enter the If-None-Match value from a request and the decoder runs the weak comparison the server uses, ignoring the W/ prefix, and tells you whether the result would be a 304.
Elsewhere in 2http: Security header audit, Request builder, Meta tag generator, HTTP status codes, MIME types, and all eleven lanes on the 2http home page. Part of the 2suite.io privacy-first ecosystem.
Common reasons are private or no-store in Cache-Control, a Set-Cookie header on the response, Vary: *, or no freshness information at all. The shared cache verdict names the reason.
max-age applies to every cache. s-maxage applies only to shared caches such as CDNs and overrides max-age there, so you can cache longer at the edge than in browsers.
For files with a content hash in the name, use public, max-age=31536000, immutable. For HTML, use no-cache with an ETag so the browser always checks for a new version.
Yes. Age tells you how long a shared cache has already held the response, and it is subtracted from the freshness lifetime to find how long the copy stays fresh.