Start with the response headers of the URL:
curl -sI https://www.example.com/path | grep -i -E 'x-cache-status|cache-status|age|cache-control|set-cookie|vary'Cache-Status says why in detail; every value is in Cache status headers.
No X-Cache-Status header
The cache wasn't involved: the answer came from the edge itself (a WAF block, a challenge, the access gate or a redirect), or the name isn't proxied through OpenWAF. Check that the request reaches the edge and, after a settings change, that the new version has propagated (Changes › Propagation).
Always DYNAMIC
detail | Fix |
|---|---|
extension | The file type isn't in the default list. Add a cache rule for it (HTML, JSON…). |
rule | A bypass rule matches. Remember the last matching rule wins. |
dev-mode | Development mode is on for the zone or the name. |
disabled | The cache is off for this name: check Scope, a name can have its own value. |
query | Caching level is No query string and the URL has a query. |
vary | The request carries a header listed in a rule's vary_bypass_if_present. |
method, upgrade, body | Only GET and HEAD without a body are cached. |
path | The path contains ;, an encoded / or \, or ends a segment with a dot. |
Always MISS or BYPASS
detail | Fix |
|---|---|
set-cookie | The origin sets a cookie on this response. Stop setting it on public assets, send Cache-Control: private="Set-Cookie", or use a rule with edge_ttl.mode override if the page is the same for everyone. |
private, no-store | The origin's Cache-Control forbids shared caches. Send public, max-age=…, or target the edge with OpenWAF-CDN-Cache-Control. |
uncacheable | No Cache-Control, Expires or default TTL applies, typically HTML made eligible by a rule. Have the origin send freshness or set an edge TTL in the rule. |
vary | The origin sends Vary with a header other than Accept-Encoding, Accept (images) or Origin. Remove it, or list it in a rule's vary_bypass_if_present. |
auth | The request had Authorization; the response must say public, s-maxage or must-revalidate to be shared. |
size | Larger than cache.max_object_mb. Raise it (up to 512). |
deception | The content type doesn't match the extension. Fix the origin's Content-Type. |
personal | A document (pdf, docx…) requested with cookies, without explicit freshness from the origin. |
status | The status code can't be stored. |
A MISS on the second request can also mean it reached another edge node: each node has its own cache.
Visitors still see old content
- Purge the URLs, a prefix, the hostname or a tag. Check Recent purges shows it applied on every node.
- With a URL purge, the query string counts:
app.css?v=2andapp.cssare different URLs. - Browsers may keep their own copy for the
max-agethey received. A purge can't clear browser caches; use versioned asset names or shortermax-agevalues. - After a deploy of a site with hashed assets, purge the HTML: old pages point to the previous build's files.
Purge answers 429
The organization hit the purge limits. Wait for the Retry-After seconds, or group values: one purge can carry up to 100 values, and a prefix or tag often replaces many URLs.
No 103 Early Hints
- The page was served from the cache (
HIT): hints are only sent when the request waits for the origin. - The node hasn't seen a shareable
200HTML answer for the page yet; request it again. - The request isn't a navigation: it needs
Accept: text/html,GET, noRange, HTTP/1.1 or HTTP/2. - The links point to an origin not listed in
early_hints.extra_origins, or aren'thttps.
See Early Hints.