OCMLABS/MODULE-CLOUDFLARE · EDGE CACHING

How storefront HTML is cached at the Cloudflare edge without caching cart, checkout or logged-in pages

  • Magento
  • Adobe Commerce
  • Hyvä

The decision is Magento’s, not a rule’s

Magento already knows which pages are safe to cache: its full page cache only stores a page when every block on it is cacheable, the request is a GET, no bypass condition applies, and the response does not set a context cookie. OCMLabs Cloudflare reuses that decision. A page the built-in full page cache would store is marked for the edge. A page it would not store is sent private, no-store. No Cloudflare rule has to guess.

The module watches Magento’s page cache kernel. When the kernel is about to save a response, a plugin adds two markers before the headers are stored: an internal edge TTL header and a Cache-Tag header built from the page’s cache tags. Because the kernel saves the headers along with the body, the markers survive on full page cache hits too, so a page served from Magento’s own cache carries the same edge headers as a fresh render.

What the edge sees

On a cacheable response, when Enable Edge Caching of HTML is on:

Cache-Control: public, max-age=0, s-maxage=3600
CDN-Cache-Control: public, max-age=0, s-maxage=3600
Cache-Tag: cat_p_12, cat_c_3, store, website, cms_b_5
  • s-maxage is the edge TTL. It comes from Edge TTL (seconds) or, when that is blank, from Magento’s full page cache TTL.
  • max-age=0 is for the browser. Returning visitors always revalidate with Cloudflare, so a purge takes effect for them as well. The “Browser Cache TTL” health check warns if the zone overrides this.
  • Cache-Tag carries the lowercased Magento cache tags for the page, which is what tag purges use. Tags are capped to fit Cloudflare’s header limits; a page that had to drop tags is counted by the “Cache-Tag header size” health check.

On every other response: Cache-Control: private, no-store. This includes bypass paths, non-GET requests, responses that set the X-Magento-Vary cookie, and every storefront response while edge caching is off.

Session cookies are stripped

A cacheable response must not hand the first visitor’s session to everyone who hits the cached copy. The module removes these Set-Cookie headers from responses it marks cacheable, the same list Magento’s Kernel and Varnish VCL use:

PHPSESSID
form_key
private_content_version
mage-cache-sessid
mage-messages

Both Laminas-set and native PHP cookies are handled. Cookies on no-store responses are left alone.

Bypass paths

Requests whose path starts with any entry in Bypass Paths are never marked cacheable, and the “Bypass protected paths” cache rule tells Cloudflare the same thing. The default list covers checkout, customer, sales, wishlist, PayPal, REST, GraphQL, the admin, downloadable products, newsletter subscription, review posting, advanced search results and the contact form. {admin} expands to your real admin frontName.

The bypass check runs twice: once when Magento decides whether to cache, and again when the response is sent, so a bypass path added after a page was stored in Magento’s full page cache is still honoured. Add the callback and notification URLs of your payment and shipping extensions to the list.

CAUTION /

Cloudflare keeps whatever it cached before you changed the bypass list until the TTL runs out or you purge. After editing Bypass Paths, purge everything from the dashboard or run bin/magento ocmlabs:cloudflare:purge —all.

Magento sets the X-Magento-Vary cookie whenever the visitor’s context differs from the default: another store view, another currency, a customer group with its own prices, or a logged-in session. Pages rendered in such a context must never be served to a default-context visitor, and the other way round.

Vary Handling: Bypass (the default, works on every plan). The “Bypass on vary cookie” cache rule sends requests carrying the cookie straight to the origin, where Magento’s own full page cache serves them. Any response that sets the cookie is marked no-store. Default-context visitors, who are the majority on most stores, get the edge.

Vary Handling: Cache key (Enterprise zones only). The cookie’s value is added to Cloudflare’s cache key, so each store view, currency and customer group is cached as its own variant at the edge. The vary bypass rule is dropped. On a non-Enterprise zone the module falls back to Bypass and says so in the rules preview and the health checks.

Query strings

With Cache Query Strings at Yes, Cloudflare caches each distinct URL including its query string, which is right for layered navigation and pagination. Set it to No to send every request with a query string to the origin; a “Bypass query strings” cache rule is added for you. Static and media paths are excluded from that rule, so versioned asset URLs stay cached either way.

Store switch URLs (___store= and ___from_store=) always bypass the edge.

Luma and Hyva

Cached HTML is safe for both themes. Both render the page anonymously and load private content after the page loads in the browser: Luma through Knockout customer-data sections, Hyva through its Alpine.js private-content loader. The module only lets Cloudflare cache a default-context anonymous render, which is exactly what Magento’s own full page cache stores. No Hyva compatibility module is needed; this module adds nothing to the storefront.

Cloudflare features that break either theme are flagged by the health checks:

FeatureLumaHyvaFix
Rocket LoaderBreaks RequireJSBreaks Alpine.jsTurn off in Speed > Optimization > Content Optimization
Auto Minify (older zones)Can break RequireJS modulesCan break Alpine.js expressionsTurn off; Magento minifies its own assets
Email ObfuscationRewrites addresses in rendered HTML and injects a scriptSameTurn off in Scrape Shield
Always OnlineServes stale prices and stock when the origin is downSameTurn off in Caching > Configuration
Browser Cache TTL other than “Respect Existing Headers”Overrides max-age=0, so purges do not reach returning visitorsSameSet to Respect Existing Headers

Checking a page by hand

Terminal window
curl -sI https://www.example.com/some-category.html | grep -iE "cf-cache-status|cache-control|cache-tag"

cf-cache-status: HIT from the second request onward means the edge is serving the page. DYNAMIC means Cloudflare did not consider it cacheable (check the cache rules and Cache-Control); BYPASS means a bypass rule matched. Cloudflare strips Cache-Tag from the response it sends to visitors, so not seeing it in curl output is expected once the page is cached.

See also

In this module