How to check if a site uses a CDN

Read the response headers with curl -s -D - -o /dev/null <url> | grep -i -E 'server|via|x-cache|cf-ray', then look for a CNAME with nslookup -type=CNAME <host> 8.8.8.8. A vendor name in either place is evidence. Neither absence is proof, because both signals can be switched off.

Why check this

A tester needs this answer before writing any cache or latency test, because a CDN changes what the numbers mean. Response times come from an edge rather than the origin, headers may be added or stripped in flight, and an origin fix can sit behind a warm cache for as long as the freshness window lasts. The failure it prevents is a bug filed against the application for a response the origin never produced. The same check confirms whether a newly configured CDN is actually in the request path.

Prerequisites

Steps

  1. Step 1.

    Read the headers most often added by an edge. server, via, x-cache and vendor-specific request identifiers all live in the response.

    curl -s -D - -o /dev/null 'https://www.cloudflare.com/' | grep -i -E '^server|^cf-ray|^cf-cache-status|^via|^x-cache'
    
    cf-ray: a398fcd37812027a-WAW
    cf-cache-status: HIT
    server: cloudflare

    Three separate signals: a vendor name in server, a per-request identifier, and a cache status header. The -WAW suffix names the point of presence that answered.

  2. Step 2.

    Run the same read against another host. A different vendor leaves a different set of headers.

    curl -s -D - -o /dev/null 'https://developer.mozilla.org/en-US/' | grep -i -E '^server|^via|^x-served-by|^x-cache'
    
    via: 1.1 google, 1.1 varnish, 1.1 varnish, 1.1 varnish
    server: Google Frontend
    x-served-by: cache-par-lfpb1150054-PAR, cache-par-lfpb1150054-PAR, cache-par-lfpb1150054-PAR, cache-fra-eddf8230067-FRA
    x-cache: MISS, MISS, HIT
    x-cache-hits: 0, 0, 1

    server names the origin platform while via lists four hops, three of them Varnish. The x-served-by entries name cache nodes in Paris and Frankfurt, so the request crossed an edge network before reaching that origin.

  3. Step 3.

    Ask DNS. A hostname pointing at a vendor-operated name through a CNAME is the clearest signal available.

    nslookup -type=CNAME developer.mozilla.org 8.8.8.8 | grep -E 'canonical name|primary name server'
    
    developer.mozilla.org	canonical name = mozilla.map.fastly.net

    The target domain names the vendor. This is the one check that survives a server stripping its own headers.

  4. Step 4.

    Run the same lookup on a host you already know sits behind an edge. The result is the reason a negative answer means nothing.

    nslookup -type=CNAME www.cloudflare.com 8.8.8.8 | grep -E 'canonical name|primary name server'
    
    	primary name server = jule.ns.cloudflare.com

    No CNAME exists. Step 1 already proved this host is served from an edge, and DNS shows an A record instead because the vendor also runs the authoritative nameservers. Only the nameserver name hints at anything here.

  5. Step 5.

    Read the headers of a host with no edge in front. The absence of every signal at once is what a direct origin looks like.

    curl -s -D - -o /dev/null 'https://httpbin.org/' | grep -i -E '^server|^via|^x-cache|^cf-ray|^age'
    
    server: gunicorn/19.9.0

    One header, and it names an application server rather than a network. No via, no cache status, no age.

How to read the result

| What you see | What it means | What to do | | --- | --- | --- | | A vendor name in server | An edge is in the path and does not hide it | Treat every timing you measure as an edge timing, not an origin one. | | via listing several hops | The request passed through proxies or caches | Count the hops. Each one can add or strip headers between origin and client. | | x-cache or cf-cache-status present | A cache is answering | Move on to the hit or miss procedure below. | | age present with no vendor header | A cache is in the path and stays anonymous | age is standard and sufficient to prove storage, whatever the vendor. | | A CNAME to a vendor domain | The hostname is delegated to that network | The strongest single signal, because DNS is outside the application's control. | | No CNAME and no vendor headers | Nothing was found | Not the same as nothing being there. Step 4 shows a host on an edge with no CNAME. |

Common mistakes

Sign: No CNAME comes back, so the site is recorded as having no CDN.Cause: A vendor that also runs the authoritative nameservers answers with an A record pointing straight at an anycast address. Step 4 shows exactly this on a host that step 1 proved is behind an edge.
Sign: A vendor name in the server header is written into the report as the CDN in use.Cause: Naming a vendor from headers is inference, not proof. Headers can be set by anything in the path, rewritten by a proxy, or left over from a layer that is no longer in use. Record the header you saw and mark the vendor as likely.
Sign: The origin looks fast in a test that reports edge numbers.Cause: A HIT is answered before the origin is involved, so the measurement describes the cache. Establish whether an edge is present before recording any latency figure, which is the reason this check runs first.
Sign: The page is behind an edge and the API on the same domain is not.Cause: CDN rules are per path and per hostname. Run the header read on the exact URL under test rather than on the home page, or a routing rule will be missed.

What to check next

FAQ

How to check which cdn a website uses?

Combine step 1 and step 3. A vendor name in server, via or a proprietary header, together with a CNAME to a domain that vendor operates, is a strong case. Either signal on its own is inference and belongs in a report as such.

How to check if a cdn is working?

Confirm the edge is in the path with steps 1 to 3, then request the same URL twice and watch the cache status header change from a miss to a hit. Presence alone says nothing about whether anything is being cached.

Can a site hide that it uses a CDN?

Yes. Vendor headers can be stripped, server can be rewritten to any string, and DNS can resolve straight to an anycast address with no CNAME. age is the hardest signal to remove, because it is required of any cache that stores a response.

Does a CDN change what my tests measure?

It changes almost all of it. Response times come from an edge, headers may be added or removed in flight, and an origin fix stays invisible until the freshness window closes. Note the CDN in the test report alongside the numbers.

Verified

Verified by Maks Vernycurl 8.21.0nslookup Windows 10.0.22631

Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.

basic6 minpublished updated Maks Verny