How to connect Cloudflare
Let xSpeed purge Cloudflare's edge cache when it purges its own, control your zone's cache level and browser TTL, and cache HTML at the edge with a free Cache Rule or APO.
If Cloudflare sits in front of your site, you have two caches — xSpeed’s and Cloudflare’s edge. Clearing one doesn’t clear the other, so publishing a post can leave visitors seeing the old version from the edge long after your own cache is fresh. Connecting the two fixes that, and lets you manage some Cloudflare settings without leaving WordPress.
Where to find it
- In your WordPress admin, click xSpeed Cache in the left menu.
- In the xSpeed Cache sidebar, open the Network group.
- Click the Cloudflare card.
Shortcut: open
wp-admin/admin.php?page=xspeed#/network/cloudflaredirectly.✅ This panel is part of xSpeed Cache (Free). Its cache level, browser TTL and APO settings are ⭐ Pro, and APO also needs a paid Cloudflare plan.

- Configuration notice — what’s still missing.
- Verification status — with Verify.
- Enable Cloudflare integration — the master switch.
- Authentication — API Token or Global API Key.
- API Token — the scoped credential.
- Zone ID — which domain to act on.
The panel is grouped: Connection holds the credentials and the verify button, Actions holds the manual purge and development mode, Purge behavior holds the auto-purge switch, and APO sits below them.
Settings at a glance
| Setting | Default | What it does |
|---|---|---|
| Enable Cloudflare integration | Off | Use the credentials below to verify and purge. |
| Authentication | API Token | Token (recommended) or legacy Global API Key. |
| API Token | Empty | Scoped token from your Cloudflare profile. |
| Account Email | Empty | Only for Global API Key auth. |
| Global API Key | Empty | Legacy full-access key. |
| Zone ID | Empty | 32-character hex ID from your domain overview. |
| Clear Cloudflare with xSpeed | On | Clear Cloudflare whenever xSpeed clears itself. |
| Cache level | Aggressive | ⭐ Pro — Cloudflare’s zone-level cache level. |
| Browser cache TTL | 14400 s | ⭐ Pro — Cloudflare’s browser cache TTL. |
Only Enable Cloudflare integration is shown at first. Every credential field below it is gated on that switch and isn’t rendered until it’s on — the screenshots here show the panel in its enabled state. The APO section is separate and stays visible either way.
How it works
xSpeed talks to Cloudflare’s API on your behalf. Once credentials are verified it can purge the edge cache, read and push zone settings, and toggle development mode.
Until you verify, auto-purge does nothing. The panel says so plainly in its notice — credentials that are present but unverified aren’t used. Fill them in, press Verify, and confirm the status changes before relying on any of it.
Credentials

- Enable Cloudflare integration — the master switch.
- Authentication — API Token or Global API Key.
- API Token — the scoped credential.
- Zone ID — which domain to act on.
- Clear Cloudflare with xSpeed — keep the two caches in step.
Use an API Token, not the Global API Key
Both work. They are not equally safe.
| API Token | Global API Key | |
|---|---|---|
| Scope | Only the permissions you grant | Full access to your entire Cloudflare account |
| Revocable individually | Yes | No — rotating it breaks everything using it |
| Needs your email | No | Yes |
A Global API Key can do anything your Cloudflare login can, across every domain in the account. Storing that in a WordPress database — where any admin-level user or a compromised plugin could read it — is a meaningful risk.
Create a token instead, at dash.cloudflare.com → My Profile → API Tokens. It needs exactly two permissions:
- Zone → Cache Purge
- Zone → Zone Settings → Edit — Read is not enough, because the development mode and APO switches write to your zone.
That token can clear your cache and adjust cache settings. It cannot touch DNS, billing, or any other domain.
⚠️ A read-only token looks like it worked. Verifying the connection and purging the cache don’t need Zone Settings: Edit, so they succeed — and setup appears complete. The failure comes later, the first time you use Dev mode or Enable APO, because those send a write your token isn’t allowed to make. If either switch refuses and the credentials are otherwise correct, check the token’s Zone Settings permission is Edit.
🔒 Treat these as credentials. They’re stored in your WordPress database, so admin access is equivalent to holding the token. Prefer a scoped token, and revoke it at Cloudflare if you ever suspect exposure.
If you use the Global API Key instead

- Authentication — switched to Global API Key.
- Account Email — your Cloudflare login email.
- Global API Key — the legacy key.
- Zone ID — unchanged between modes.
Switching Authentication swaps the field set. The API Token field disappears and two take its place:
- Account Email — the email you sign into Cloudflare with. Only used in this mode; the token path doesn’t need it, because a token identifies itself.
- Global API Key — found at
dash.cloudflare.com→ My Profile → API Tokens → Global API Key.
Zone ID stays in both modes, since it identifies which domain to act on rather than how you authenticate.
Your token settings aren’t lost when you switch — the two credential sets are stored separately, so switching back restores what you had.
🔒 Two credentials instead of one, and both more dangerous. This mode stores your Cloudflare login email and a key with full account access in
wp_options. Together they’re enough to sign into the API as you, across every domain in the account. Use it only if scoped tokens genuinely aren’t an option for you.
Zone ID
The 32-character hex ID for your domain, on its Cloudflare overview page. It identifies which zone to act on — an account with several domains has a different Zone ID for each, and pointing at the wrong one purges someone else’s site.
Clear Cloudflare with xSpeed
On by default, and the main reason to connect at all. When xSpeed clears its own cache — after a post save, a settings change, a manual purge — it triggers a Cloudflare purge too. That’s what keeps the two layers from disagreeing.
Automatic edge purges, and ones run from WP-CLI, record their outcome in the activity log — “Purged the Cloudflare edge cache”, or “Cloudflare purge failed” with Cloudflare’s reason. A purge that couldn’t reach the edge is no longer something you’d only discover from a stale page.

- Purge Cloudflare edge — clears everything Cloudflare holds for the zone, on demand.
- Development mode — bypasses the edge entirely for three hours, so you see your real output while changing a theme.
- Clear Cloudflare with xSpeed — the switch above, in its own row.
A purge no longer has to clear the whole zone. When only a few URLs changed, xSpeed purges exactly those and says so — “Purged 3 URLs from the Cloudflare edge cache”. When a change touches more URLs than are worth purging one by one, it falls back to the whole zone and records why. A queued purge that can no longer run — the connection was removed in the meantime — is skipped and logged rather than retried silently.
Cache level, browser TTL, and APO
⭐ This section is part of xSpeed Pro. APO also needs a paid Cloudflare plan.

- APO availability — whether your plan supports it.
- APO status — errors surface here.
- Cache level — Cloudflare’s zone-level setting.
- Browser cache TTL — what Cloudflare tells browsers.
Cache level doesn’t mirror Cloudflare’s zone setting so much as be it — xSpeed passes your choice straight through to Cloudflare’s cache_level API. So these are Cloudflare’s behaviours, listed here under both names:
| Level | Cloudflare calls it | Behaviour |
|---|---|---|
| Basic | No Query String | Serves from cache only when the URL carries no query string at all. |
| Simplified | Ignore Query String | Ignores the query string — one cached copy answers every variant. |
| Aggressive (default) | Standard | Caches every static asset including query-string variants — usually what you want. |
Browser cache TTL is what Cloudflare tells browsers, and it snaps to the nearest legal value — Cloudflare only accepts specific numbers (0, 30, 60, 300, 1800, 3600, 7200, 14400, and so on). Enter something else and it rounds rather than erroring. The field itself accepts 0–31536000 seconds (up to a year).
Both are stored locally first. Editing them changes xSpeed’s copy; Sync to Cloudflare pushes them to your zone. That two-step is deliberate — you can stage changes without touching the live zone until you’re ready.
Checking whether Cloudflare is caching your pages
By default Cloudflare caches static files only — images, CSS, JavaScript. It caches your HTML only when you tell it to, and there are two ways:
- A Cache Rule, on any Cloudflare plan including Free. Add a Cache Rule set to Eligible for cache, then keep
/wp-admin/,/wp-login.php,/wp-json/,/wp-cron.phpand checkout, and the logged-in, comment and cart cookies (wordpress_logged_in_,comment_author_,wp_woocommerce_session_), out of it. Cache WordPress HTML on Cloudflare’s free plan walks through these rules and the order they go in. On an xSpeed site, use its rules 1 to 3 and skip rule 4, the Edge TTL override: see Using a Cache Rule with xSpeed. - APO, Cloudflare’s paid WordPress integration, which this panel switches on. See APO below.
So when you open your browser’s Network tab and look at the page request, you’ll see:
cf-cache-status: DYNAMIC
That is normal, and it does not mean anything is broken. DYNAMIC means Cloudflare didn’t cache that page — the default for every WordPress site without a Cache Rule or APO. Your pages are still being served from xSpeed’s own cache, which is what x-xspeed-cache: HIT (nginx) or HIT (php) on the same response tells you.
Static files are different. They show cf-cache-status: HIT once an edge has a copy, and MISS when it doesn’t yet. Seeing MISS repeatedly isn’t a fault either — Cloudflare has many edge locations and each one caches separately, so the first visitor routed through each location gets a MISS.
| Header | On a page request | On a static file |
|---|---|---|
cf-cache-status: DYNAMIC | Normal without a Cache Rule or APO — Cloudflare isn’t caching HTML | Not expected |
cf-cache-status: MISS | Normal with a Cache Rule or APO — this edge has no copy yet | Normal — this edge has no copy yet |
cf-cache-status: BYPASS | With a Cache Rule: the edge refused this response. Once, on a page xSpeed hasn’t cached yet, it’s normal. Every time, see below | Not expected |
cf-cache-status: HIT | Only with a Cache Rule or APO — served from the edge | Normal — served from the edge |
BYPASS on every load means the page always reaches Cloudflare marked as not for keeping. The usual causes:
- Your host sends
no-cacheon every page, from its own server settings rather than from WordPress. Check thecache-controlheader on a page that also showsx-xspeed-cache: HIT: if it isn’tmax-age=…, something after xSpeed rewrote it. Ask your host to stop, since xSpeed already marks the pages that must not be kept. - The page sets a cookie (
set-cookieon the response), often a session or analytics plugin. Cloudflare never keeps a response that sets a cookie. Cloudflare’s own__cf_bmcookie doesn’t count. - Separate mobile cache is on, or the address has a query string xSpeed can’t purge, such as a tracking parameter. xSpeed marks those
privateon purpose.
To have Cloudflare cache your HTML too, add the free Cache Rule above, or switch on APO if you’d rather Cloudflare maintain the WordPress exclusions for you.
Using a Cache Rule with xSpeed
A Cache Rule only decides that Cloudflare may keep your pages. How long it keeps each one, and when it lets go, comes from xSpeed, so check these settings:
- Page Cache is on. The edge keeps only pages xSpeed has already cached. Those go out with
Cache-Control: max-age=…, set by Page lifetime in Browser Cache, one hour by default. A page xSpeed is still building, or one for a logged-in visitor, goes out asprivate, no-cache, and the edge leaves it alone. - Cloudflare is connected on this panel and Clear Cloudflare with xSpeed is on. Then xSpeed’s purge, after you save a post or press Purge all, clears the edge too. Without it an edited page stays stale at the edge until its lifetime runs out.
- CDN or proxy in front, in Page Cache’s settings, is on Detect automatically (the default) or Cloudflare. That is how xSpeed knows Cloudflare is in front, and it adds
CDN-Cache-Control: no-storeto the pages the edge must not keep. - Separate mobile cache is off, unless your theme really shows phones a different page. Cloudflare can’t tell a phone from a desktop at the same address, so with it on xSpeed marks every page
privateto keep the wrong one from reaching the other device, and the edge caches no HTML at all.
Don’t set the rule’s Edge TTL to Ignore cache-control header. It would override the private and no-store answers above and could hand a logged-in page to the next visitor. The blog’s rule 4 is for sites whose server marks every page no-cache; xSpeed doesn’t, so it isn’t needed here.
APO
Automatic Platform Optimization is Cloudflare’s maintained way to cache your HTML at the edge: it keeps the WordPress cookie and path exclusions up to date for you, where a Cache Rule leaves them to you. Either way a visitor can get a complete page from a nearby edge without your server being involved at all.
It requires a paid Cloudflare Pro or Business plan, or the $5/month APO add-on. On a plan without it, Cloudflare refuses to switch APO on: the panel shows “Cloudflare not reachable” with the button disabled, or Enable APO returns Cloudflare’s error. That’s a plan limitation, not a fault. The free Cache Rule above does the same job.
⚠️ Edge HTML caching changes what your hit ratio means, whether it comes from APO or a Cache Rule. With HTML cached at the edge, most requests never reach your origin — so Page Cache’s hit ratio is labelled origin and counts only what got through. A low-looking number isn’t a problem; it means the edge is doing its job.