How To Verify If Your CDN Is Respecting Cache Headers
Learn how to check if your CDN honors cache headers and delivers optimal content caching for improved site performance.

You deploy a fix, flush the cache in your dashboard, hard refresh in your browser, and your site still serves the wrong version. At that point it feels like the CDN is ignoring you.
In reality it almost never is. It is following rules from headers and settings that are not fully lined up.
This guide shows you how to verify CDN cache headers. You will see what your origin says, what the CDN says, where they disagree, and how to fix that without guesswork.
Step 1: Know What You Are Telling Caches
Before you touch commands, you want a simple mental picture. Without it, cache-control headers CDN verification feels random.
Private Cache vs Shared Cache
Think of two separate layers.
- Private cache
Your user’s browser cache. It is allowed to store user specific responses. - Shared cache
Your CDN and any proxy between you and users. It must not leak one user’s response to others.
When you write headers you are talking to both layers. Some directives are meant for browsers, some for shared caches, some for both.
{{promo}}
Core Cache-Control Directives You Actually Need
Here is a compact reference you can keep open while you work.
Two key rules:
- If s-maxage is present, the CDN uses that and ignores max-age.
- The browser ignores s-maxage and uses max-age.
If you skip s-maxage, your CDN may follow internal defaults or dashboard rules. That is when you start to feel that the CDN is not respecting cache headers.
Step 2: See What The CDN Is Sending To Users
Now you know what you want to say. Next you need to read what the CDN is actually delivering.
You will use two tools:
- curl for clean raw headers
- Browser dev tools for a visual view
Together they give you the full picture when you troubleshoot CDN cache header issues.
Use Curl for a Realistic Request
You want a normal GET request, not a HEAD request.
Run: curl -svo /dev/null https://yourdomain.com/asset.css
What this does for you:
- Sends a full GET, just like a browser
- Shows request and response headers
- Discards the body so the output stays readable
In the output, look for:
- Cache-Control
- Age
- Any CDN status header such as cf-cache-status, X-Cache, Cache-Status
If you see Age greater than zero, the response came from a shared cache. That is strong proof that the CDN cached the object.
Run the same command again. On the second run, Age should be higher. If it stays missing or zero, the CDN is probably not caching that URL at all.
Use Browser Dev Tools Like a First Time Visitor
curl is great, but you also want to see what a real user gets.
Steps:
- Open the site in Chrome or Firefox.
- Open DevTools.
- Go to the Network tab.
- Check Disable cache.
- Reload the page.
Now the browser is forced to go to the network instead of its own cache.
Pick a static asset, for example style.css or a main image:
- In Headers, check Cache-Control and any CDN status header.
- In Size, look for:
- A normal file size which means a network fetch.
- Later, once you uncheck Disable cache, you want to see (from disk cache) or (from memory cache) for browser hits.
When you uncheck Disable cache and reload:
- If the browser now pulls from its own cache, your max-age is working.
- If it still hits the network for every request, something in Cache-Control is blocking it.
At this point you already know a lot about CDN respecting cache headers for that asset.
Step 3: Compare Origin Headers Versus CDN Headers
The real test is simple. You ask one question.
Does the origin say one thing while the CDN delivers something else.
To answer that, you need two views: through the CDN, and direct to the origin.
Capture the CDN version
You already saw this command. Now save it into a file.
curl -svo /dev/null https://www.yourdomain.com/asset.css > cdn_headers.txt 2>&1
This represents what real users see in production.
Capture the Origin Version with Curl Resolve
If you know your origin IP address, you can bypass DNS for one request.
curl -svo /dev/null \
--resolve "www.yourdomain.com:443:1.2.3.4" \
https://www.yourdomain.com/asset.css > origin_headers.txt 2>&1
Here you are saying:
For this one call, when you connect to www.yourdomain.com on port 443, use IP 1.2.3.4.
You now have:
- cdn_headers.txt
- origin_headers.txt
Open both and check:
- Did Cache-Control change
- Did any header appear on origin and vanish at CDN
- Did any header appear only at CDN
If origin sends Cache-Control: public, max-age=600, s-maxage=86400 and the CDN sends the same, that means check if CDN honors origin cache settings has passed for that URL.
If CDN sends a very different Cache-Control value, you know something in the CDN settings is rewriting headers.
Step 4: Common Reasons Your CDN Seems To Ignore Headers
Once you compare origin and edge, patterns start to repeat. Most issues fall into a handful of buckets.
Problem 1: Origin says "do not cache"
Sometimes the CDN is doing exactly what it was told. The origin headers just never meant what you thought.
Watch out for these on public assets:
- Cache-Control: private
- Cache-Control: no-store
- Cache-Control: no-cache
- Cache-Control: max-age=0
- Set-Cookie headers on CSS, JS, images, fonts
Shared caches read those as clear signals that content is user specific or sensitive. Many CDNs refuse to cache in that case and report status values like BYPASS or DYNAMIC.
Fix:
- Stop sending Set-Cookie for truly static files.
- Remove strict directives from files that should be public and shared.
- Replace them with something like public, max-age=600, s-maxage=86400.
Problem 2: Vary and query string rules
Vary and query string settings control how many versions of a response the CDN keeps.
Two classic traps:
- Vary: User-Agent or Vary: *
This spreads cache entries across countless keys and destroys your hit ratio. Some CDNs respond by refusing to cache. - Query string mode that does not match your URL design
If you use style.css?v=4 for versioning but the CDN ignores query strings, users will keep getting the old file. On the other side, if the CDN treats every tracking parameter as unique, you fragment your cache
When you troubleshoot CDN cache header issues, always check:
- What Vary looks like on origin responses
- How your CDN is configured to treat query strings
Fix:
- Keep Vary: Accept-Encoding for compression. Avoid user agent based Vary on shared assets.
- Align CDN query string mode with how you version your URLs.
Problem 3: Dashboard rules that override headers
Many providers let you override origin headers with panel rules.
For example:
- Cloudflare cache rules that set an Edge Cache TTL
- CloudFront cache policies that enforce min and max TTL
- Akamai properties that ignore origin headers unless you enable honoring them
In these setups, the order is often:
- Dashboard rule
- Origin header
- Default CDN heuristics
So if a rule says cache for one day, it wins even if origin sends a ten minute max-age.
To check this, you go back to your origin and CDN header diff. If the CDN value always matches a rule from the panel, you know your configuration is in charge, not the header.
That is still a valid state, as long as you know it is happening.
Step 5: CDN Custom Caching Headers Best Practices
Now you know how to check behavior. Next you want to set things up so your CDN always gets clear, explicit instructions.
These patterns keep your cache behaviour predictable.
Speak Directly to the CDN with s-maxage
Instead of relying on CDN defaults, give shared caches their own TTL.
Good pattern for HTML or APIs:
Cache-Control: public, max-age=60, s-maxage=300
You are saying:
- Browsers: treat this as fresh for one minute
- CDNs: treat this as fresh for five minutes
This reduces load on origin without leaving users on stale content for long.
This is one of the easiest CDN custom caching headers best practices you can apply. It is simple and works across many providers.
Version Static Assets and Make them Immutable
If you ever change a file, change its URL.
You can do that by:
- Putting a hash in the filename
app.8c6d7a4.js - Using a version parameter
app.js?v=5
Once you do that, you can safely make assets long lived.
For example:
Cache-Control: public, max-age=31536000, immutable
Browsers and CDNs will keep that file for a year and skip revalidation.
When you ship a new version, it sits at a new URL and triggers a fresh fetch.
Split Browser and CDN Policies
In some setups you want a stricter rule for browsers than for CDNs. That is when custom headers shine.
Examples:
- CDN-Cache-Control for shared caches in general
- Cloudflare-CDN-Cache-Control for Cloudflare only
- Surrogate-Control for Fastly and reverse proxies
Pattern:
Cache-Control: private, max-age=300
CDN-Cache-Control: public, s-maxage=3600
Here you are telling:
- Browsers: this is user specific and can stay in private cache for five minutes
- CDNs: treat it as public and safe to share for one hour
This gives you more control than trying to stretch one header across every layer.
{{promo}}
Conclusion
A CDN is not a stubborn black box. It is a strict listener that follows headers, cache keys, and dashboard rules in a fixed order. When you line up those parts and verify CDN cache headers with simple tools like curl and browser dev tools, the behaviour becomes predictable.
The next time someone says the CDN is ignoring your rules, you will have a clear, repeatable way to prove what is really happening.
FAQs
How do I verify if my CDN is respecting cache headers?
You can verify CDN cache headers by sending a real request with curl and by checking the Network tab in your browser. Look at Cache-Control, Age, and the CDN status header. If origin and CDN headers match and Age increases between calls, your CDN is respecting cache headers.
Why does my CDN ignore my Cache-Control max-age value sometimes?
Many CDNs treat max-age as a browser hint only. If you do not set s-maxage, the CDN may follow its own default TTL or panel rules. To make your intent clear, send headers like public, max-age for browsers and s-maxage for shared caches so cache-control headers CDN verification becomes easier.
How can I troubleshoot CDN cache header issues safely?
Start by collecting two sets of headers, one through the CDN and one direct to origin. Compare Cache-Control, Vary, Set-Cookie, and any CDN status header. Then review query string rules and dashboard cache policies. This way you troubleshoot CDN cache header issues without touching live traffic behaviour for users.
What are CDN custom caching headers best practices?
Good CDN custom caching headers best practices include versioning static assets, using public, max-age for browsers, and s-maxage for CDNs, and adding immutable to versioned files. For more control, use CDN-Cache-Control or vendor specific headers so you can give separate rules to browsers and shared caches.
How do I check if my CDN honors origin cache settings vs panel rules?
First, check what your origin sends using curl with a direct resolve. Then check the CDN response for the same URL. If TTLs or directives differ and always match a rule you set in the dashboard, the panel is in charge. That tells you how CDN honors origin cache settings in practice.


.png)
.png)
.png)





