Common reasons Cloudflare fails to cache your content

By default, Cloudflare only caches a predefined list of static file extensions (images, CSS, JS, fonts). HTML pages and dynamic application routes are passed directly to your origin with cf-cache-status: DYNAMIC. On content-driven sites, those uncacheable HTML responses often represent most of the traffic, which mechanically caps the hit ratio shown in the dashboard even when every asset is cached. Beyond that default behavior, several technical factors commonly prevent caching:

  • Conflicting origin HTTP headers: Directives like Cache-Control: no-store, private, or max-age=0 force Cloudflare to bypass edge caching entirely (status BYPASS).
  • Unintended Set-Cookie headers: If your backend framework (WordPress, Laravel, Node.js) issues session cookies on public pages, Cloudflare prevents edge caching to avoid cross-user session leakage.
  • Fragmented Query Strings: Marketing and analytics tracking parameters (UTMs, gclid, fbclid) create distinct cache keys for identical assets, resulting in repeated cache MISS events.
  • Conflicts between legacy Page Rules and modern Cache Rules: Outdated rule ordering can override edge TTL instructions and cause unpredictable caching behavior.

The fastest way to identify which factor applies to your zone is to read the response headers directly. HIT means the edge served the object, MISS means it had to fetch it from the origin, BYPASS means a rule or header explicitly disabled caching, and DYNAMIC means the URL is not considered cacheable at all. If your origin is drowning in uncached requests, the strain often surfaces elsewhere first, for example as intermittent 521, 522, or 524 origin errors.

A proven approach to reaching 80%+ cache hit ratios

To turn Cloudflare into an effective performance shield without breaking interactive application features:

  • Implement granular Cache Rules: Define specific Edge TTL rules with automatic bypass when authentication, checkout, or cart cookies are present.
  • Separate Browser TTL from Edge TTL: Leverage the s-maxage header or Cloudflare edge settings to keep resources cached in edge nodes while maintaining control over client-side freshness.
  • Normalize Query Strings: Strip or reorder tracking parameters to unify cache keys without degrading analytics tracking.
  • Enable Tiered Cache: Direct regional edge data centers to pull from centralized upper-tier hubs, drastically reducing round-trips to your origin infrastructure.

One last principle: cache aggressively at the edge but stay conservative in the browser. The edge cache is under your control and can be purged in one click, while browser caches sit on machines you cannot reach. Separating the two TTLs is what makes long edge caching safe for frequently updated content.

Fixing it step by step: a practical checklist

Work through these steps in order. Each one isolates a specific failure mode before you touch any setting, so you always know which change actually fixed the problem. More field-tested checklists like this one are collected in our Cloudflare guides hub.

  1. Inspect the edge headers. From any terminal, request a representative URL and look at the caching headers:
    curl -sI https://www.example.com/page | grep -iE "cf-cache-status|cache-control|set-cookie|cf-ray"
    The cf-cache-status value tells you why the object was or was not cached, and cf-ray encodes the datacenter that answered (for example CDG for Paris). Repeat the test on a static asset and on an HTML page, since they usually behave differently.
  2. Compare with the origin response. Query your origin server directly, bypassing the proxy, to see what headers it really sends:
    curl -sI --resolve www.example.com:443:203.0.113.10 https://www.example.com/page
    Replace the IP with your actual origin address. Any no-store, private, max-age=0, or Set-Cookie on a public page explains a BYPASS status immediately.
  3. Audit Cache Rules in the dashboard. Open Caching > Cache Rules and list every rule on the zone. Cloudflare evaluates them top to bottom, but when several rules match the same request, the last matching rule wins on every setting they both define. A permissive legacy rule placed at the end can therefore silently override everything above it. Also check Rules > Page Rules for old entries still overriding Edge TTL.
  4. Create one explicit cache rule for cacheable content. Match the hostnames and paths that are safe to cache, set Edge TTL to a value matching your publish cadence (one day for editorial pages, one month for versioned assets, for example), and in the same rule bypass cache when a session or cart cookie is present, so authenticated users never receive a shared copy.
  5. Normalize the cache key. In the Cache Rule, under Cache key, ignore query string order and strip known tracking parameters (utm_*, fbclid, gclid). This collapses hundreds of duplicate cache entries for the same asset into one.
  6. Enable Tiered Cache. Go to Caching > Tiered Cache and activate Smart Tiered Caching. Regional datacenters then fetch from upper-tier hubs instead of your origin, which matters as soon as you serve traffic from many countries.
  7. Purge, then re-test. Run Caching > Configuration > Purge Everything, then repeat the curl -I test. Expect MISS on the first request and HIT on the second; if the second request is still BYPASS or DYNAMIC, go back to step one and check the headers again.

Common mistakes that keep the hit ratio low

  • Caching HTML without a cookie bypass: Serving one shared edge copy of a page that renders per-user data can expose one visitor's session content to another. Always pair aggressive HTML caching with an explicit bypass on authentication, cart, or session cookies.
  • Stacking conflicting rules: Mixing old Page Rules, Cache Rules, and origin headers that each set a different TTL produces behavior that changes from one datacenter to another. Pick a single source of truth, usually Cache Rules, and remove the rest.
  • Chasing a 100% hit ratio: Dynamic endpoints, POST requests, and admin paths will never be cached, and they should not be. Measure the ratio on cacheable assets; a healthy zone typically shows 80 to 95% on those, not on total traffic.
  • Changing a TTL without purging: Objects already stored at the edge keep the TTL they were cached with. After any TTL change, purge the cache, otherwise users keep seeing stale content for hours and you may wrongly conclude the new rule does not work.
  • Testing the wrong hostname: Comparing www.example.com with the apex domain, or hitting a staging hostname with different DNS records, leads to false conclusions. Always confirm with cf-ray that you are looking at the zone and datacenter you think you are.

Frequently asked questions

Why does cf-cache-status show DYNAMIC on files I expected to be cached?

DYNAMIC means the URL does not match the default list of cacheable file extensions, which is most often the case for HTML pages. Anything outside that list needs an explicit Cache Rule to become eligible for the edge cache. Double-check the exact path you requested, because one directory can behave differently from another.

Are Cache Rules available on the Free plan?

Yes. Cache Rules, query string normalization, and Tiered Cache are included on every plan, including Free; only the number of active rules grows with paid plans. Upgrading is only needed for advanced options such as cache reserve or higher rule quotas, not for the fixes described in this guide.

How fast do Cache Rule changes take effect?

Rule changes propagate to the edge within seconds. Objects already stored, however, keep the TTL they were cached with, so run a purge after changing a rule if you want the new behavior applied immediately. In practice, a Purge Everything followed by a few warm-up requests is enough to verify the result.

Can a low hit ratio affect my SEO?

Indirectly, yes. Uncached responses make pages slower, which degrades Core Web Vitals, and an origin overloaded by uncached bot traffic can start serving errors to crawlers. If search engines repeatedly receive errors or timeouts, indexing suffers; our guide on accidental Googlebot blocking and SEO drops covers the diagnosis from the crawler side.

Need expert help offloading your origin and boosting Core Web Vitals?

CF Garage inspects your HTTP headers, audits cache flows, and configures custom edge caching rules tailored to your application. Fixed pricing, measured and guaranteed results.

View our offers

Related topics