Start here
Troubleshooting
How to check that caching is working, what each bypass reason means, and what to do when something looks wrong. Work through the sections in order: most problems are answered by the first two.
1. Is caching working?
The quickest check: view source
Open your home page in a private or incognito browser window, so that you
are not logged in. Reload it once, then view the page source
(Ctrl+U on Windows, Cmd+Option+U on a Mac) and scroll to the very
bottom. On a cached page you will see a line like this:
<!-- Caching Out - page generated and cached on 2026-09-10 08:14:02 UTC -->
That comment is added to the stored copy only, so the first anonymous visit to a page will not have it: that visit is the one that generates and stores the page. From the second anonymous visit onwards the comment is there, and its timestamp tells you when the stored copy was made. If it never appears no matter how many times you reload, something is preventing the page from being cached. Carry on below.
Log out first
A logged-in user never receives a cached page. This is a fixed safety rule and cannot be switched off: the cached copy is shared between everyone who sees it, so serving it to a logged-in visitor could show one person's private content to another. If you are logged in to wp-admin you are always looking at an uncached page, even in another tab. Use a private window.
The debug header
For a precise answer, switch on the debug header. Add this line to
wp-config.php, above the line that says "That's all, stop editing":
define( 'CACHINGOUT_DEBUG', true );
Every response now carries an X-CachingOut-Cache header with one of three
values:
| Value | Meaning |
|---|---|
HIT | The page was served from the cache. WordPress did not run. |
MISS | The page was generated fresh. It is stored for next time. |
BYPASS:<reason> | The page was not served from cache, and <reason> names the exact rule that stopped it. |
A normal, healthy page goes MISS on the first anonymous visit and HIT
on every visit after that until the cache is cleared or expires. Remove the
CACHINGOUT_DEBUG line when you are finished; it is a debugging aid, not a
setting to leave on.
How to read a response header in your browser
- Open the page in a private window and press
F12to open developer tools (Cmd+Option+Ion a Mac). - Click the Network tab, then reload the page.
- Click the very first row in the list. It has the same name as the page.
- Look under Response Headers for
x-cachingout-cache.
Header names are shown in lower case by most browsers. Reload a second time
before drawing a conclusion: the first load after a change is expected to
be a MISS.
One thing the header cannot tell you
Some rules only apply once the page has already been generated: a page that
returns an error, sets a login cookie, or contains a form security token.
By then the MISS header has already been sent. So a page that reports
MISS on every single visit and never becomes a HIT is being generated
but refused at the storage step. The likely reasons are in the second half
of the table below.
2. Every bypass reason
<name>, <pattern> and <code> below are filled in with the actual
value on your site.
Reasons you may see in the header
| Reason | What it means | What to do |
|---|---|---|
BYPASS:kill-switch | CACHINGOUT_DISABLE_CACHE is set to true in wp-config.php. | Intended. Remove that line to resume caching. See section 7. |
BYPASS:disabled | The "Enable page caching" switch on the Cache tab is off. | Switch it on. |
BYPASS:method:<METHOD> | The request was not a GET, for example a form submission (POST). | Nothing. Only GET responses can be shared between visitors. |
BYPASS:ajax | The request went to wp-admin/admin-ajax.php. | Nothing. Correct behaviour. |
BYPASS:wp-admin | The request was for a page under /wp-admin. | Nothing. Correct behaviour. |
BYPASS:wp-login | The request was for wp-login.php. | Nothing. Correct behaviour. |
BYPASS:wp-register | The request was for wp-register.php. | Nothing. Correct behaviour. |
BYPASS:rest-api | The request went to a /wp-json/ endpoint. | Nothing. Correct behaviour. |
BYPASS:feed | The request was for an RSS or comments feed. | Nothing. Correct behaviour. |
BYPASS:robots | The request was for /robots.txt. | Nothing. Correct behaviour. |
BYPASS:sitemap | The request was for an XML sitemap. | Nothing. Correct behaviour. |
BYPASS:php-file | The URL ends in .php, for example xmlrpc.php. | Nothing. Correct behaviour. |
BYPASS:static-asset | The URL ends in an image, stylesheet, script, font or media extension. Those are served by the web server, not the page cache. | Nothing. Their caching is handled by Browser Caching. |
BYPASS:logged-in | The visitor is logged in to WordPress. | Nothing. Log out or use a private window to test. |
BYPASS:variation-cookie:<name> | The visitor carries a language or currency cookie that changes what the same URL shows, so a shared copy could be the wrong language or currency. | See "Language cookies" below. |
BYPASS:session-cookie:<name> | The visitor has a PHP session (PHPSESSID). A session ties a page to one person. | See "Every page bypasses with a session cookie" below. |
BYPASS:store-cookie:<name> | The visitor has a WooCommerce or Easy Digital Downloads cart or store session cookie. | Nothing. A shopper with a cart is always served live. |
BYPASS:cookie:<name> | The visitor has a cookie from your own "Never cache when these cookies are present" list. Pro. | Adjust or remove that entry if it is too broad. |
BYPASS:user-agent:<pattern> | The visitor's browser identification matches one of your excluded user agents. Pro. | Adjust or remove that entry. |
BYPASS:query-string | The URL has a query parameter that is not on your "Ignored query parameters" list, for example ?ref=newsletter. The common tracking parameters (fbclid, igsh, gclid, ttclid, utm_* and others) are on the list by default since 1.21.17. | If the parameter is a tracking tag that does not change the page, add it to "Ignored query parameters" on the Cache tab; if a default is missing, use "Restore default parameters" there. Leave out any parameter that changes what the page shows. |
BYPASS:woocommerce-cart | A /cart/ URL. | Nothing. Never cached, by design. |
BYPASS:woocommerce-checkout | A /checkout/ URL. | Nothing. Never cached, by design. |
BYPASS:woocommerce-account | A /my-account/ URL or a WooCommerce account endpoint such as /order-received/, /view-order/, /edit-account/, /edit-address/, /lost-password/, /payment-methods/, /orders/ or /downloads/. | Nothing. Never cached, by design. |
BYPASS:edd-purchase-history | An Easy Digital Downloads /purchase-history/ URL. | Nothing. Never cached, by design. |
BYPASS:edd-purchase-confirmation | An Easy Digital Downloads /purchase-confirmation/ or /purchase-receipt/ URL. | Nothing. Never cached, by design. |
BYPASS:excluded-path | The URL matches one of your own "Never cache these URLs" patterns. Pro. | Adjust or remove that pattern. |
BYPASS:exclusion:<id> | A rule added by one of the plugin's compatibility modules matched. <id> names the rule. | Usually intended. The name says which module asked for it. |
Reasons decided after the page was generated
These stop the page being stored. They are not shown in the header, because
it has already been sent. The symptom is a page that is always MISS and
never HIT.
| Reason | What it means | What to do |
|---|---|---|
BYPASS:kill-switch | The kill switch also blocks writing. | See section 7. |
BYPASS:status:<code> | The page did not return 200 OK. A redirect, a 404 or a server error. | Only successful pages are stored. If a page you expect to work reports a code here, fix the page. |
BYPASS:nonce | The HTML contains a WordPress security token that has to be fresh for each visitor. A cached token breaks form submissions. | Usually a form on the page. Logout links in menus are already allowed for and do not cause this. |
BYPASS:set-cookie:auth | The response set a WordPress login cookie. | Nothing. Correct behaviour. |
BYPASS:set-cookie:session:<name> | The response started a PHP session. | See below. |
BYPASS:set-cookie:store:<name> | The response opened a cart or store session. | Nothing. Correct behaviour. |
BYPASS:set-cookie:<name> | The response set a cookie from your own excluded-cookie list. Pro. | Adjust or remove that entry. |
Every page bypasses with a session cookie
If every page reports BYPASS:session-cookie:PHPSESSID, a plugin or theme
starts a PHP session for every visitor. A session ties a page to one
person, so Caching Out never shares it. This is built in and cannot be
switched off. Find the plugin that starts the session (deactivate plugins
one at a time, or check the Page Audit) and ask its author for a setting
that limits the session to the pages that need one. Caching resumes as soon
as visitors stop receiving the cookie. Detail:
kb/01-page-caching.md.
Language cookies
If your own browser never gets a cached page but an external test does, and
the reason is variation-cookie:pll_language, wp-wpml_current_language or
_icl_current_language, your multilingual plugin has given you a language
cookie. When each language has its own URL the cookie is ignored, because
the URL already says which language to serve. When every language shares one
URL, the cookie is the only thing that says which language the page is in,
so those visitors are served live on purpose. Currency cookies from
multi-currency plugins always bypass for the same reason. Detail:
kb/01-page-caching.md.
3. Changes are not showing
Work down this list in order.
- Are you logged in? Logged-in visitors always see live pages, so what you see may already be correct while visitors see the old copy. Check in a private window.
- Clear the cache. Use Purge Cache on the Cache tab or in the admin bar. The cache is normally cleared automatically when you publish or update a post or page, approve or edit a comment, switch theme, activate or deactivate a plugin, save widgets or the customizer, or when WooCommerce stock or price changes. If your change came from somewhere else, clear it by hand.
- Check the lifespan. Cached pages are regenerated after the Cache Lifespan set on the Cache tab, ten hours by default. A page you did not purge may simply not have expired yet.
- Clear your own browser cache. Static files are told to be kept for a
long time on purpose. Reload with
Ctrl+Shift+R(Cmd+Shift+Ron a Mac), or test in a private window. - Updated a CSS or JS file by hand? Browsers keep the old copy until the file's version number changes. Change the version in your theme or plugin so the URL changes.
- Using a CDN or a proxy? Cloudflare, Varnish, Sucuri and your host's own edge cache keep their own copies. Purge there too. Caching Out Pro can do this for you from the Add-ons tab.
- WebP or AVIF images not appearing (Pro)? With
CACHINGOUT_DEBUGon, the response headerX-CachingOut-Image-Variantsays which copy of the page was served:avif,webpornone.nonein Safari is expected (it does not announce the formats).noneeverywhere means the copies were not found: check the.webp/.aviffiles exist beside the originals (or inwp-content/uploads-webpc/), are smaller than the originals and were made after them, then purge the cache.
More: kb/01-page-caching.md.
4. The site looks broken after switching something on
Page caching itself does not change how a page looks: it stores what your site already produced. Visual faults almost always come from the file and media optimization settings. Switch them back off in this order, checking the site after each one. Purge the cache after every change, and look in a private window.
- Optimize CSS Delivery (Pro). The most likely cause of a layout that jumps, a menu that becomes a plain list of links, or a page that renders unstyled for a moment.
- Combine CSS and JS (Pro). The next most likely, especially with page builders.
- Defer JavaScript, then Delay JavaScript. The usual symptom is a
slider, lightbox, map or chart that never starts, with an error like
X is not definedin the browser console. - LazyLoad (images and videos). The usual symptom is images that never appear, or a self-hosted video that no longer plays.
Once you know which setting caused it, switch that one back on and use its exclusion list instead of leaving the whole feature off. Every optimization feature has one: Excluded CSS, Excluded JS, the Delay JS exclusion list and the LazyLoad exclusions. Add the affected file or script, one at a time, until the fault is gone. The full list of known symptoms and their fixes is in kb/05-file-optimization.md and kb/04-media-optimization.md.
If you cannot reach wp-admin
Two lines in wp-config.php switch whole subsystems off without touching
your settings:
define( 'CACHINGOUT_DISABLE_OPTIMIZATION', true );
define( 'CACHINGOUT_DISABLE_CACHE', true );
The first stops every CSS, JavaScript and media optimization from running; the second stops all page caching. Your saved settings are untouched, so removing the lines restores exactly what you had. Add the first alone if the site looks wrong; add the second if pages are being served that should not be.
5. The Filesystem Check rows
Caching Out > Filesystem Check is a read-only look at everything the plugin needs in order to work. It changes nothing. Each row is marked OK, Attention or Problem, and anything that is not OK carries a suggested fix.
The Re-run filesystem check button repeats the activation writes (the
drop-in, WP_CACHE, the cache directory) and refreshes the results. It is
the right first response to most Problem rows. The same button appears on
the activation notice in wp-admin.
| Row | What it checks | If it is not OK |
|---|---|---|
| Cache kill switch | Whether CACHINGOUT_DISABLE_CACHE is set | Attention means caching is deliberately off. Remove the line from wp-config.php to resume. |
| WP_CACHE constant | Whether WordPress will load the drop-in | Problem means nothing is cached. Re-run the check, or add the line by hand. If it keeps disappearing, your host manages wp-config.php. |
| advanced-cache.php drop-in | Whether the drop-in exists and is the copy Caching Out installed | Missing: re-run the check. Belongs to another plugin: page caching is blocked until that plugin goes. Does not match: another plugin replaced it, or it is from an older version. |
| Runtime settings snapshot | The settings file the drop-in reads | Save any settings page once. It is rewritten on every save. |
| Cache directory | That wp-content/cache/cachingout/ exists and is writable | Purge the cache, which recreates it. If that fails, your host is blocking writes to wp-content/cache/. |
| Cache directory guards | The index.php and .htaccess files that stop the folder being browsed | Purge the cache; the guards are recreated with the folder. |
| Bundled libraries | That the bundled minifier shipped with your copy | Reinstall from the official zip. Pages still cache normally without it; only JavaScript minification is unavailable. |
| Background task wiring | That every scheduled job has something listening for it | Deactivate and reactivate the plugin. Reinstall from a fresh zip if it persists. |
| Leftovers from other cache plugins | Folders, files and .htaccess blocks left by a removed caching plugin | See section 6. |
With Caching Out Pro active, four more rows appear:
| Row | What it checks |
|---|---|
| Optimize CSS delivery | Which stylesheets were kept render-blocking on the last uncached view of your front page, and why. Kept stylesheets are the feature working as intended. |
| Load jQuery in the footer | Whether jQuery actually moved to the footer, or which scripts in the page head are keeping it where it is. |
| Defer jQuery (opt-in) | Whether jQuery was deferred, and which inline scripts still reference it and will now run before it. |
| Change record (Activity) | Whether changes are being recorded, and whether the record's database table exists. |
6. Leftovers from a previous cache plugin
Removing another caching plugin rarely removes everything it created. The "Leftovers from other cache plugins" row lists what it found, with the exact path of each item and whether deleting it is safe. Only plugins that are no longer installed are reported.
One kind of leftover changes behaviour: a # BEGIN ... block in .htaccess
that still contains rules. Apache keeps applying them, and Caching Out
refuses to write its own browser caching rules while they are there rather
than mix two plugins' rules in one file. Back up .htaccess, delete that
block from its # BEGIN line to its # END line, then save the Browser
Caching tab again.
Everything else, empty marker pairs and abandoned folders and config files, is inert. Delete it with your file manager or FTP client when you are ready. Caching Out never deletes another plugin's files. It only tells you where they are. Detail: kb/02-browser-caching.md and server-config.md.
7. Emergency: switch caching off completely
If pages are being served that should not be, or the site is behaving
strangely and you need it back now, add this one line to wp-config.php,
above the line that says "That's all, stop editing":
define( 'CACHINGOUT_DISABLE_CACHE', true );
This takes effect on the very next page load. From that moment:
- No page is served from the cache. Every visitor gets a freshly generated page.
- No page is written to the cache.
- The drop-in stops before it does anything at all.
- Your settings are not changed, and the stored cache files are not deleted.
This is the documented emergency measure and it works in every version of the plugin. Use it before deactivating anything: it is faster, reversible, and does not need wp-admin access.
To revert: delete the line again, or change true to false, then
purge the cache once so nothing stale is left over. The Filesystem Check
"Cache kill switch" row confirms which state you are in.
If the plugin's optimizations rather than its caching are the problem, use
CACHINGOUT_DISABLE_OPTIMIZATION instead. See section 4.
8. What to send when you contact support
The more of this you include, the faster the answer:
- Versions. The Caching Out version, and the Caching Out Pro version if you use it, both from the Plugins screen. Add your WordPress and PHP versions and your server type (Apache, NGINX, LiteSpeed or IIS).
- The debug header value. Switch on
CACHINGOUT_DEBUG, load the affected page in a private window, and copy the wholeX-CachingOut-Cachevalue, including the part afterBYPASS:. Say which URL it came from. See section 1. - The Filesystem Check state. Open Caching Out > Filesystem Check and copy the table, or attach a screenshot. Include every row, not only the failing ones.
- The Activity export (Pro). The Export for support button on the Activity page and on the Filesystem Check page downloads a JSON file of what the plugin changed and when. Secrets are redacted in the file. Attach it; it answers "what changed just before this started?" without anyone having to guess.
- What you changed, and when it started. Which setting you switched on, what the page did before, and what it does now.
- The URL of an affected page, reachable without logging in if possible. Please do not send passwords or login details.
9. The Page Audit cannot read a page
The audit reads each tracked page the way a visitor would, by requesting
your site's own public address from your server (a loopback request). If
that request fails, the page shows The page could not be fetched for
auditing, with the reason underneath, for example cURL error 7 (could
not connect) or a timeout.
The usual causes:
- The host or a firewall blocks a site from requesting itself. Some hosts do this by default. WordPress's own Tools > Site Health check "Your site can perform loopback requests" fails in the same case; send that result to your host and ask them to allow it.
- The server cannot reach its own domain name. Common on a staging or development copy whose address only resolves on your computer, inside a container, or behind a login wall in front of the whole site.
- The page took too long. Try again once the site is warm, or audit a lighter page first.
Nothing else depends on it: caching, purging and the rest keep working. The PageSpeed measurement on the Insights tab (Pro) is run by Google from outside, so it works even when the audit cannot. Without the audit there is no "Compress this image" button on the hero finding; with Caching Out Pro you can open any image from the Media Library instead (image compression).