Your store survives a traffic spike. And then the chargebacks start. In the post-mortem we published recently, a WooCommerce store hit 2,400 duplicate orders in six hours because one Cloudflare “Cache Everything” page rule cached the order-confirmation page and served it to every visitor who opened the same URL. Different customers, same order. Same receipt. Same shipping address.
That store was lucky nobody else’s data leaked. Cached checkout pages don’t just duplicate orders — they leak customer names, addresses, and card details (last four digits) to strangers.
The good news: this is fully preventable, and the fix takes about five minutes. In this guide you’ll learn exactly which pages must never be cached, how to configure a Cloudflare Cache Rule that bypasses them, how to verify the fix, and what to check when orders are still duplicating.
Why Cloudflare Caching Breaks WooCommerce
Cloudflare’s job is to serve identical, static responses to thousands of visitors. But a WooCommerce checkout is the opposite of static. Every request to /checkout/ depends on:
- PHP session and cart cookies — the visitor’s cart contents are not in the HTML;
- WooCommerce nonces — security tokens embedded in checkout forms, valid per-user and per-session;
- Authentication state —
/my-account/renders completely different HTML for logged-in customers, and customers don’t add themselves to Cart and Billing details on the server; that data is customer-specific; - Order state —
/order-received/is generated after a payment completes and belongs to exactly one order.
When Cloudflare caches any of these pages, the first response is stored and replayed to everyone. Carts look empty, checkouts show the wrong totals, order confirmations show a stranger’s name, and customers hammer the “Place order” button because nothing seems to happen — each click creating a new order as documented in the Cloudflare Community thread on duplicate orders.
WooCommerce itself tries to protect you: the checkout page ships a Cache-Control: no-store header. The problem is almost never the header — it’s that something overrides it. “Cache Everything” page rules, edge cache rules, or a misconfigured full-page cache plugin re-enable caching regardless of what WooCommerce asked for.
Signs Your Checkout Is Being Cached
You don’t need to be the victim of 2,400 duplicates to know you have a problem. Watch for these symptoms:
- Another customer’s data visible — name, address, or order number on your screen;
- Duplicated orders — the same purchase recorded two or more times, especially during traffic spikes;
- Cart contents stuck or empty — items don’t update after “Add to cart”;
- “Order received” shows a different order than the one you just paid for;
- Checkout errors appear only for some visitors — cached HTML plus nonce expiry is a recipe for intermittent failures.
If you see any of these, check the response headers on /checkout/ before doing anything else:
curl -sI https://yourstore.com/checkout/ | grep -iE 'cache-control|cf-cache-status'
A healthy response shows cache-control: no-store and cf-cache-status that is not HIT. If you see cf-cache-status: HIT on the checkout URL, your checkout is cached. Fix it now.
The Fix: One Cloudflare Cache Rule
Cloudflare has been moving away from Page Rules — the “Cache Everything” rule from the post-mortem is exactly the kind of footgun they replaced. Cache Rules let you match requests precisely and set cache eligibility per path. The community consensus on best practice is to replace Page Rules with Cache Rules, not run both — conflicting rules create exactly the override behavior that broke the store above.
Step 1 — Open Cache Rules
Log in to Cloudflare → your domain → Caching → Cache Rules → Create rule.
Step 2 — Match the WooCommerce URLs
Give the rule a name (e.g., “WooCommerce bypass”). In the Expression field, switch to the Expression Editor and paste:
(http.request.uri.path contains "/checkout/") or (http.request.uri.path contains "/cart/") or (http.request.uri.path contains "/my-account/") or (http.request.uri.path contains "/order-received/") or (http.request.uri.path contains "/wc-api/") or (http.request.uri.path contains "/add-to-cart/") or (http.request.uri.path contains "/wp-admin/")
If you renamed your WooCommerce pages (check under WooCommerce → Settings → Advanced → Page setup), use those slugs instead — the rule matches the literal path.
Step 3 — Set cache eligibility to Bypass
In Cache eligibility, choose Bypass cache. This tells Cloudflare: don’t store a response for these paths, and always forward the request to origin. Note what bypassing does not do: your security features (WAF, rate limiting, bot fight mode, DDoS protection) all still operate on these requests — you’re only skipping the cache layer.
Click Deploy and allow a minute for propagation.
Step 4 — Verify
Re-run the header check on all protected URLs:
curl -sI https://yourstore.com/checkout/ | grep -iE 'cache-control|cf-cache-status'
curl -sI https://yourstore.com/cart/ | grep -iE 'cf-cache-status'
cf-cache-status should now be BYPASS or DYNAMIC on every WooCommerce page. Then run a real checkout test in an incognito window: add to cart, pay, confirm the order — twice, in two different browser profiles. No shared data, no duplicates.
Beyond the Bypass: The Rest of Your Cache Stack
The Cloudflare rule removes the CDN layer of risk. But a cached checkout can equally come from your own cache stack, which is why we treat caching as a hierarchy — see our deep dive on edge caching vs object caching and the cache category for the full picture. Check these three layers:
- Page-cache plugins. WP Rocket, LiteSpeed Cache, and similar full-page caches exclude
/cart/,/checkout/,/my-account/andwc-apiby default — keep those exclusions intact. If you “optimized” a plugin’s exclusion list to cache more, undo it. If you use Cloudflare APO, the WooCommerce exclusions are built in, but verify APO vs WP Rocket behavior before enabling both. - Server/edge caches. Nginx FastCGI cache, Varnish, or a CDN origin shield can cache any URL that looks “static.” If you can’t find where the caching happens, run the WordPress Speed Diagnosis tool and look at the response headers chain — each
X-Cacheorageheader identifies the layer that served the page. - Headers. WooCommerce sends
Cache-Control: no-store, no-cache, must-revalidate, max-age=0on checkout pages, andSet-Cookieon stateful pages. Never add a blanket header-cleaning rule (like “remove Set-Cookie”) on Cloudflare, because stripping cookies makes pages more cacheable — the exact opposite of what WooCommerce needs. Our post-mortem covers the full header chain and why “Cache Everything” overrode no-store.
Why the Checkout Should Stay Fast Anyway
Store owners worry that bypassing the cache makes checkout slow. It doesn’t — and expecting an uncacheable page to come from the CDN was never realistic. What matters for checkout speed is: a fast origin (TTFB), a lean checkout template, and minimizing JavaScript on that page — we benchmark exactly this in WooCommerce checkout speed and AJAX. Meanwhile, all your truly cacheable pages (home, category, product, blog) stay on the CDN, which is where your Core Web Vitals and LCP improvement lives. Correct caching is selective caching.
Orders Still Duplicating? Check These Three Things
If the Cloudflare rule is in place, headers are clean, and duplicates persist, the cause is usually downstream of the CDN as outlined in the duplicate-order prevention guides:
- Payment gateway retries — gateways refund-and-retry silently on “timeouts,” creating double charges. Use an idempotency key per order (Stripe, PayPal, and most gateways support one).
- Browser double-submits — the customer clicks “Place order” twice. Disable the submit button on click and use WooCommerce’s built-in order-key dedupe.
- Webhook + cron double-processing — payment webhooks arriving twice must be made idempotent; a growing backlog in
wp_woocommerce_ordersoften signals webhook replays.
After the fix, watch failed-order and duplicate-count metrics for 48 hours. If your edge case is unusual, our WooCommerce category is a curated map of the failure modes we’ve tested at scale.
FAQ
Does bypassing the cache slow down my checkout page? No. Checkout is per-user, session-bound, and dynamic — it was never truly cacheable. The bypass removes stale pages and duplicate orders; the page itself can be made fast at the origin (lean template, minimal JS, good TTFB), which is where the real gains are.
Should I use Cloudflare Cache Rules or Page Rules? Cache Rules. They’re the modern, more flexible replacement, and mixing the two creates conflicting overrides — the exact failure mode that caused the duplicate-order incident. Migrate existing WooCommerce page rules to a single cache rule.
Can I cache the /order-received/ page? Never. It’s unique per order and contains customer data. Caching it was the root cause of the 2,400 duplicate orders in our post-mortem.
Will bypassing these paths hurt my Core Web Vitals? Your Core Web Vitals are scored across your most-visited pages (home, catalog, product). Those remain cached and fully optimizable. For stores, we cover the full LCP/INP/CLS toolkit in the Core Web Vitals section.
What if my checkout still caches after this rule? Check for a second cache layer (page-cache plugin, Varnish, origin shield) serving the URL before Cloudflare sees it, and confirm your slugs match the rule. Re-test with the diagnosis tool to trace which layer responds.