A while ago I came across Jono Alderson’s HTTP Caching Guide, and even after years of working with web performance, I learned things I didn’t know. The guide is thorough - covering everything from Cache-Control directives to CDN behaviour to font preloading gotchas.

Reading through it, I kept thinking: “I should check if my sites are doing this right.” Then I opened DevTools, looked at the headers on a few assets, and realised I’d be there all day. A typical WordPress page pulls in 20+ files. Checking each one manually against best practices? That’s exactly the kind of tedious work a script should handle.

So I built one.

What I wanted to catch

The guide covers a lot of ground, but some issues stood out as particularly common (and particularly wasteful):

  • no-store on static assets — Your browser re-downloads that 200KB JavaScript file on every single page load.
  • Missing immutable on fingerprinted assets — You’ve got app.a1b2c3d4.js with a hash in the filename, but you’re still telling browsers to revalidate it. Why?
  • Vary: User-Agent — Congratulations, you’ve just fragmented your CDN cache into thousands of variants.
  • immutable on HTML — This one’s dangerous. Lock users into stale content and watch the support tickets roll in.

What Cache Checker does

The tool fetches a URL, extracts all the assets from the HTML (scripts, stylesheets, images, fonts), and analyses each one against a set of caching best practices.

It looks at the usual suspects:

  • Cache-Control directives (max-age, s-maxage, no-cache, no-store, immutable, stale-while-revalidate)
  • Expires, ETag, Last-Modified
  • Vary headers (and whether they’re causing cache fragmentation)
  • Age header (to see if you’re actually hitting CDN cache)

But it also does some smarter things:

  • Detects fingerprinted assets — Files with hashes like style.d4e5f6.css can be cached aggressively. The tool recognises these patterns and adjusts its recommendations.
  • Identifies CDN usage — It checks response headers for Cloudflare, Fastly, Akamai, Vercel, and others. CDN presence changes what “good” caching looks like.
  • Checks CORS on fonts — If you’re using <link rel="preload"> for fonts, you need proper CORS headers or preload silently fails.
  • Analyses redirect caching — 301 redirects should be cached. Many aren’t.

Each issue gets categorised by severity: error, warning, or info.

Running it

I built a few ways to use this:

WP-CLI (if you’re in the WordPress ecosystem):

wp cache-check https://example.com

Standalone PHP (no WordPress needed):

php standalone.php https://example.com

Alfred Workflow (for quick checks from anywhere on macOS): There’s an Alfred 5 workflow included in the repo. Type your trigger keyword, paste a URL, and get the results without leaving whatever you’re working on. Handy when you’re reviewing a client site or want to quickly sanity-check something.

Cloudflare Worker (offload the work to the edge): This version runs on Cloudflare’s network-distributed IPs and no load on your origin server. Useful if you’re checking sites you don’t control.

One caveat with the Worker: some hosting providers block Cloudflare’s IP ranges, which can cause checks to fail. If you’re getting connection errors on certain sites, that’s likely why. The standalone PHP version running from your own machine won’t have this problem.

Output comes in three flavours: plain text for humans, JSON for automation, and HTML tables if you want something visual.

What I learned building this

A few things surprised me:

Fingerprinting detection is trickier than expected. You can’t just regex for hex strings-you’ll get false positives on things like colour codes in filenames. I ended up looking for patterns like [name].[hash].[ext] where the hash is 8+ characters of hex or base64.

CDN detection is a rabbit hole. Every CDN has its own set of headers. Cloudflare uses cf-ray, Fastly uses x-served-by, Vercel uses x-vercel-id. And some sites stack multiple CDNs, which makes things interesting.

Vary is underrated as a footgun. I found sites with Vary: User-Agent, Accept-Encoding, Cookie on static assets. That’s not caching. That’s chaos with extra steps.

The stack

  • PHP 8.0+ for the WordPress plugin and standalone versions
  • JavaScript for the Cloudflare Worker
  • No external dependencies in the PHP version (just cURL and DOM parsing)

If you want to dig into the caching theory behind this, Jono Alderson’s guide is the best resource I’ve found. For font loading specifically, You’re Loading Fonts Wrong is worth a read.


The code is on GitHub: github.com/ilicfilip/http-cache-checker

If you find caching issues I’m not catching, open an issue - there’s always another edge case.