Updated on July 13, 2026

WordPress Cache Headers: How to Tell If Your Page Is Actually Cached

A practical guide to reading WordPress cache headers, testing CDN and page-cache layers, and diagnosing hits, misses, bypasses, cookies, and query strings.
Dark 3D cache path connecting a WordPress page, page-cache layer, CDN edge, and origin server with green status checks
Table of Contents

WordPress cache headers can tell you whether a page came from a browser, a CDN, a page cache, or the origin server. The hard part is that one request may pass through all four layers.

I often see a cache plugin marked as active while the public page still feels slow or shows old content. In other cases, a header says MISS even though caching works correctly. Looking at one line in isolation creates more confusion than clarity.

This guide shows a repeatable way to test a public WordPress page. You will learn which headers matter, why different cache layers can disagree, and what to check before changing plugin or Cloudflare settings.

The short answer: one header cannot prove the whole page is cached

A useful cache check needs at least three requests: a normal request, the same request again, and a request with a harmless query string. Compare the full response each time. A healthy setup may show a page-cache hit at the origin, a CDN miss on the first visit, and a CDN hit on the second.

That sequence matters more than any single value. For example, CF-Cache-Status: MISS usually means Cloudflare did not serve that response from its edge cache. It does not prove that WordPress generated the page from scratch. An origin page cache may still have served the HTML quickly.

Header or signal Layer it describes What to look for
CF-Cache-Status Cloudflare edge cache HIT on a repeated public request
Age Shared cache A value that appears or increases on repeated requests
Plugin-specific cache header WordPress page cache A clear HIT or equivalent origin-cache signal
Cache-Control Browser and shared-cache instructions Rules that fit the page type and cache architecture
Set-Cookie Application or session Unexpected cookies that may make a public page uncacheable
Vary Cache-key variation Which request headers create separate cached versions

What WordPress cache headers actually describe

The browser asks for a URL. A CDN may answer first. If it does not, the request reaches the server, where a page-cache plugin or server cache may return stored HTML. Only then does WordPress need to run PHP, query the database, and build the page dynamically.

Each layer reports its own decision. Cloudflare describes the edge result. FlyingPress, WP Rocket, a host cache, or Nginx may describe the origin result. Browser-oriented directives describe what the visitor’s browser may store. None of those values automatically explains every other layer.

This is also why a site can have a good WordPress caching setup without returning identical headers from every URL. A blog post, cart, account page, API response, and logged-in preview should not all follow the same cache policy.

A practical cache test you can repeat

1. Choose a safe public URL

Start with a published page that should be cacheable, such as a service page or blog post. Do not begin with checkout, cart, account, a preview, or a logged-in administrator view. Those pages often need dynamic responses by design.

Open a private browser window or use a command-line request without WordPress login cookies. Keep the URL consistent. Redirects, trailing-slash changes, and alternate hostnames can make two requests look similar while they use different cache keys.

2. Record the first response

The first request may warm an empty edge cache. Save the status code and all response headers. Do not conclude that caching is broken simply because you see MISS. A miss can be a normal first step.

Check whether the page-cache layer reports a hit. Also note Cache-Control, Age, Vary, Set-Cookie, the final URL, and any CDN-specific values. The official Cloudflare APO verification guide documents the headers that identify an APO response and the conditions that can prevent an edge hit.

3. Repeat the exact same request

Wait a few seconds, then request the same URL again. A working CDN cache often changes from MISS to HIT. An Age header may appear, while the WordPress page-cache value remains a hit.

If the second request still misses, do not immediately purge everything. Look for a cookie, a bypass rule, a query string, an authorization header, a short cache lifetime, or HTML that changes on every response. Then check whether the origin cache still prevents a full WordPress render.

4. Add a harmless cache-busting query

Test a URL such as ?cache-check=timestamp. This request should not change the page content. It may bypass the edge or create a separate cache key, depending on the CDN configuration.

A bypass here can be healthy. It proves that query-string handling differs from the clean URL. The important question is whether ordinary visitors and search crawlers receive the correct, fast, canonical page without the test parameter.

5. Test the user journey, not only the homepage

Repeat the clean test on one blog post, one service page, and any template that receives meaningful traffic. Then test dynamic pages separately. A cache rule that helps a public article can break a cart, form, membership area, or personalized account.

Our speed optimization service checklist covers the broader checks around cache exclusions, mobile behavior, logged-in sessions, forms, and conversion paths.

A quick command-line example

You can inspect headers without downloading the page body. On macOS or Linux, run curl -I https://example.com/page/, wait a few seconds, and run the same command again. Use curl -I "https://example.com/page/?cache-check=123" for the cache-busting comparison.

Follow redirects when needed with curl -IL, but read the final response block rather than the first redirect. Save the output if you plan to change a setting. Before-and-after evidence makes it much easier to tell whether a rule fixed the cache path or simply warmed one object.

Command-line requests do not reproduce every browser condition. They may use a different user agent, lack consent cookies, and reach a different CDN location. Treat them as a clean baseline, then confirm the public page in a private browser. When WordPress cache headers differ between those tests, compare cookies, request headers, redirects, and the responding edge location before drawing a conclusion.

A real multi-layer result from Webless

I tested a recent Webless article twice with a normal public request, then once with a harmless query string. The first clean request returned a Cloudflare MISS while the origin page-cache header reported HIT. That meant Cloudflare contacted the origin, but WordPress did not necessarily rebuild the page.

Eight seconds later, the second clean request returned a Cloudflare HIT, an Age: 8 value, and the same origin page-cache hit. The edge had stored the response after the first visit and served the repeated request.

The cache-busting query returned BYPASS at Cloudflare and MISS at the page-cache layer. APO also identified the query string as the reason. That was expected test behavior, not a failure on the clean article URL.

This small sequence explains why WordPress cache headers need context. If I had looked only at the first Cloudflare value, I could have called a working stack broken. If I had looked only at the page-cache hit, I would have missed whether the edge actually stored the page.

How to read common cache results

HIT

The cache found a stored response and served it. Confirm which layer emitted the value. A CDN hit and a page-cache hit are related, but they are not the same event.

MISS

The requested version was not in that cache. The cache may store the response for the next request. A miss after a purge, deployment, expiry, or first visit can be normal.

BYPASS or DYNAMIC

A rule or request condition prevented cache delivery. Common causes include cookies, query strings, authorization, response directives, dynamic page rules, or explicit exclusions. The cause may be intentional.

EXPIRED or STALE

The cache had an older response. It may contact the origin to refresh it, or serve a stale copy under an allowed resilience rule. Check the CDN’s exact definition before treating either value as an error.

No cache status at all

The response may not pass through the layer you expected, or that system may not expose a public header. Confirm DNS, proxy status, plugin configuration, and the final responding hostname. Also check whether another tool removed or renamed diagnostic headers.

Why Cache-Control can look contradictory

Cache-Control is important, but modern WordPress stacks can apply additional edge logic. A response might include conservative browser instructions while a configured CDN still stores the HTML under its own rules. Conversely, a long browser lifetime does not prove that an edge or server page cache works.

WordPress also sends no-cache directives for several dynamic and authenticated situations. That protects previews, administration, and personalized responses from being reused in the wrong context. Replacing those headers globally to make a test look green can expose private or stale content.

Read the directive beside the edge status, the origin-cache status, cookies, and the page type. If Cloudflare APO is part of the stack, our Cloudflare APO guide explains what it adds beyond a normal WordPress page cache.

Five conclusions to avoid

  • “MISS means caching is broken.” A first request or expired object can miss normally.
  • “HIT means the whole site is fast.” Images, scripts, fonts, database calls, and third parties can still delay the experience.
  • “Every URL should be cached.” Checkout, accounts, previews, searches, and personalized pages need careful exclusions.
  • “Purging fixes the problem.” A purge removes stored objects; it does not repair the rule, cookie, or response that caused a bypass.
  • “One test represents every visitor.” Device, location, login state, query strings, and CDN data centers can change the path.

What to check when a public page never reaches a hit

First, confirm that the response is a public 200 page with the expected canonical URL. Then remove login cookies and test the clean URL twice. Inspect unexpected Set-Cookie values, query strings, cache-control directives, and CDN bypass reasons.

Next, check exclusions in the WordPress cache plugin and CDN. Review whether a security, consent, ecommerce, localization, or personalization plugin changes every response. Compare the HTML or response headers between requests to find a value that prevents reuse.

Finally, measure origin performance as well. A CDN can hide a slow uncached response until the cache expires or a visitor requests a new variation. Our guide to PageSpeed Insights and Core Web Vitals explains why a fast test and real visitor experience can still diverge.

Turn the result into a safe optimization decision

A reliable cache review ends with a page-by-page decision. Public, stable HTML usually benefits from full-page caching. Dynamic and personalized journeys need exclusions. Static files need sensible browser lifetimes. Purge and preload behavior must match how often content changes.

Do not change several layers at once. Fix the clearest cause, purge the affected caches, and repeat the same three-request sequence. That gives you evidence instead of a temporary improvement you cannot explain.

If the stack includes WordPress page caching, host caching, Cloudflare, ecommerce, and personalized content, the interactions can become risky. Webless WordPress speed optimization services include cache-layer diagnosis, safe exclusions, public verification, and performance testing across the pages that matter.

Good WordPress cache headers do not need to look identical on every request. They need to show that each layer makes the right decision for the visitor and the page.

If your clean public pages never settle into a clear pattern, send the URL through the Webless contact page. We can trace the request from edge to origin and identify whether the real issue is cache policy, WordPress performance, or both.

NOT SURE WHAT IS SLOWING YOUR SITE DOWN?

Request a WordPress Core Web Vitals report to see which loading, responsiveness, stability, and accessibility issues deserve attention first.