How to Detect Google Cloud CDN on Any Website (API Guide)
Google Cloud CDN is the quiet one. Cloudflare announces itself with a CF-Ray header on every response, CloudFront stamps its request IDs on everything it touches, and Fastly leaves a via: 1.1 varnish trail. Google’s edge adds a single, easily overlooked line: via: 1.1 google. There is no Google-owned CNAME suffix to look for, no distinctive nameserver, and often no Google certificate either, because customers bring their own.
This guide covers what Google Cloud CDN actually is and how it differs from plain Google Cloud hosting, the exact header that reveals it, the supporting signals that raise your confidence, why DNS cannot confirm it, how to check by hand with curl and browser DevTools, and how to check hundreds of domains at once with the DetectZeStack API. Every response in this post comes from a live scan run while writing it.
What Google Cloud CDN Is (and How It Differs From Plain Google Cloud Hosting)
Cloud CDN is not a separate product you point a CNAME at. It is a checkbox on a backend service behind Google Cloud’s global external Application Load Balancer. When it is enabled, cacheable responses from the origin are stored at Google’s edge points of presence and served from there on subsequent requests. When it is disabled, the same load balancer still terminates TLS at the same edge and still proxies traffic through the same Google Front End (GFE) fleet; it just does not cache.
That architecture matters for detection. Every signal that reveals Cloud CDN is really a signal that traffic passed through Google’s global edge. A site can be “on Google Cloud” in several ways that never touch that edge: a Cloud Run service on its default run.app hostname, an App Engine app on appspot.com, a static site served straight from a Cloud Storage bucket, or a Compute Engine VM with a public IP. Those leave DNS and TLS fingerprints, which are covered in how to detect Google Cloud hosting. Cloud CDN leaves HTTP fingerprints instead, and a site can show one set without the other.
So the question this post answers is narrower than “does this site use Google Cloud?” It is “does this site serve traffic through Google’s global edge, where Cloud CDN lives?”
The Signals That Reveal Google Cloud CDN
The Via: 1.1 google Response Header
Via is a standard HTTP header defined in RFC 9110. Each proxy on the path between the origin and the client is supposed to append an entry naming the protocol version it received and a pseudonym for itself. Google’s edge proxies write 1.1 google. If that is the only proxy in the path, the header is exactly:
via: 1.1 google
This is the primary Cloud CDN fingerprint, and it is the one DetectZeStack matches. The pattern in the fingerprint database is anchored on both ends (^1\.1 google$), so it fires when the header value is exactly 1.1 google and nothing else. That exactness is worth knowing about, because Via is cumulative. If another proxy sits behind or in front of Google’s edge, the value becomes a list. During testing, www.spotify.com returned via: HTTP/2 edgeproxy, 1.1 google, 1.1 varnish and www.fitbit.com returned via: 1.1 google, 1.1 google. Both clearly pass through Google’s edge, and neither matches the anchored pattern, so neither is reported as Google Cloud CDN by the API today. The batch script later in this post adds a raw header check to catch those cases.
When the pattern matches, the API reports Google Cloud CDN under the CDN category with source: "http" and confidence 100. The fingerprint also carries an implication: Google Cloud CDN implies Google Cloud, so a second entry appears under IaaS even though no separate Google Cloud pattern matched. You will see both in the live response below.
What the header proves, precisely: via: 1.1 google is written by the Google Front End for any global external Application Load Balancer, whether or not Cloud CDN caching is switched on for that backend. The technology name is Google Cloud CDN because that is the product this edge exists to deliver, but if you need to know that caching is actually active, look for a cache hit: an Age header alongside a public Cache-Control. During testing, www.snapchat.com returned age: 3146 with cache-control: public, max-age=10800, s-maxage=10800, which is an edge-cached response.
Supporting Signals: Google Trust Services TLS Certificates and Google Cloud Trace Headers
Three more signals often travel with the Via header, and each one is detected separately, so a fully Google-native site lights up several entries at once.
- Server: Google Frontend. When the origin does not set its own
Serverheader, the GFE fills inGoogle Frontend. DetectZeStack reports this as Google Cloud Load Balancing under Load balancers. It is absent whenever the origin setsServeritself;www.snapchat.comreportsserver: API Gatewayandwww.wix.comreportsserver: Pepyaka, and both still carryvia: 1.1 google. - X-Cloud-Trace-Context. Google’s load balancer injects this distributed-tracing header on the way to the origin, and many origins echo it back. Its presence is reported as Google Cloud Trace under Performance. It also implies Google Cloud.
- Google Trust Services certificate. If the site uses a Google-managed certificate on the load balancer, the issuer organization is Google Trust Services. DetectZeStack inspects the issuer during every scan and reports a Google Cloud entry from the TLS layer at confidence 70 when nothing from the HTTP layer already claimed the name. Many Cloud CDN customers upload their own certificates instead:
www.snapchat.compresents a DigiCert certificate andwww.wix.compresents Let’s Encrypt, and the API reports those issuers under SSL/TLS certificate authority. The absence of a Google certificate therefore proves nothing.
www.waze.com shows all of the above at once, which is why it is the example domain in the API section:
$ curl -sI https://www.waze.com | grep -iE "^(via|server|x-cloud-trace-context):"
x-cloud-trace-context: 8c0cc98b4a24b90329c500fd18217f61
server: Google Frontend
via: 1.1 google
$ echo | openssl s_client -connect www.waze.com:443 -servername www.waze.com 2>/dev/null \
| openssl x509 -noout -issuer
issuer=C = US, O = Google Trust Services, CN = WR3
Why DNS Alone Cannot Confirm Cloud CDN (Load Balancer Anycast IPs, No CNAME)
DNS is the most reliable layer for most infrastructure detection, and it is the wrong layer for this one. Google’s external load balancer gives each customer a dedicated global anycast IP address. Customers publish that IP in an A record, or CNAME their public hostname to another hostname they own, and nothing in the chain ends in a Google-controlled suffix. Two of the domains from this post illustrate it:
$ dig www.snapchat.com CNAME +short
web-gcp.api.snapchat.com.
$ dig www.wix.com CNAME +short
cdn1.wixdns.net.
Snapchat’s intermediate hostname literally contains gcp, but that is a naming choice, not a signature anyone can rely on. Wix’s chain stays entirely inside wixdns.net. Both sites return via: 1.1 google. The Google DNS suffixes DetectZeStack does match (run.app, appspot.com, cloudfunctions.net, storage.googleapis.com, ghs.googlehosted.com) identify specific hosting products, not the CDN edge. Reverse lookups on the anycast IP are no better, because the PTR records are generic. For Cloud CDN, read the headers.
Manual Detection With curl and Browser DevTools
For a single domain, one curl call is enough. Use -I for a HEAD request, or -sD - -o /dev/null if the site rejects HEAD, and filter for the headers above:
$ curl -sI https://www.snapchat.com | grep -iE "^(via|server|age|cache-control|x-cloud-trace-context):"
server: API Gateway
via: 1.1 google
cache-control: public, max-age=10800, s-maxage=10800, stale-while-revalidate=5400
age: 3146
Read it top to bottom: the origin sets its own Server header, Google’s edge appended via: 1.1 google, the response is cacheable, and it has been sitting in the edge cache for 3146 seconds. That is a Cloud CDN hit.
In a browser, open DevTools, switch to the Network tab, reload, click the document request at the top of the list, and expand Response Headers. The via line appears in the alphabetical list. The Network tab is also the easiest way to spot a multi-hop value like 1.1 google, 1.1 varnish, which tells you a Varnish tier sits behind Google’s edge. If you want to be sure a response really came from the edge cache rather than the origin, compare age across two reloads a few seconds apart; a growing value is a cached object.
Why Manual Detection Breaks at Scale (Prospect Lists, Multi-CDN Audits, Cloudflare in Front)
The manual check takes ten seconds per domain and produces an unambiguous answer. It also produces exactly one bit of information, and it does not scale past a couple of dozen domains before three problems show up.
Prospect lists. If you sell something that integrates with Google Cloud, a list of 2,000 domains that already terminate traffic at Google’s edge is a qualified list. Building it by hand means 2,000 curl calls, plus parsing, plus re-running the ones that timed out, plus doing it again next quarter. And via alone does not tell you what else is on the stack, which is usually the part that decides whether the lead is worth a call.
Multi-CDN audits. Security and platform teams inventory every CDN their organization’s domains depend on. The same organization can have marketing on Cloudflare, an app on Google Cloud CDN, and a legacy property on CloudFront. A header-by-header grep per CDN is five different greps, and the multi-hop Via cases need their own handling.
Cloudflare in front. When Cloudflare proxies a site whose origin is behind Google’s load balancer, Cloudflare strips or rewrites the upstream headers by design. From the outside, the site is a Cloudflare property; via: 1.1 google never reaches you. No scanning approach sees through that, and a detection pipeline needs to record “Cloudflare, origin unknown” rather than “not Google”. The broader CDN-versus-origin question is covered in how to detect the CDN and hosting provider of any website.
An API that returns the whole stack as structured JSON in one call, and can take ten domains per request, turns all three from scripting projects into a filter on a response.
Detect Google Cloud CDN With the DetectZeStack API
The DetectZeStack scan fetches the page, matches the response headers and body against the fingerprint database, resolves the CNAME chain, and inspects the TLS certificate, then returns everything as one JSON object. For Google Cloud CDN the header match does the work, and the other layers fill in the rest of the stack.
The public /demo endpoint needs no API key, is limited to 20 requests per hour per IP, and returns the same shape as the authenticated endpoint. This is the exact response for www.waze.com, captured while writing this post:
$ curl -s "https://detectzestack.com/demo?url=www.waze.com" | jq '.'
{
"url": "https://www.waze.com",
"domain": "www.waze.com",
"technologies": [
{
"name": "Google Cloud",
"categories": ["IaaS"],
"confidence": 100,
"description": "Google Cloud is a suite of cloud computing services.",
"website": "https://cloud.google.com",
"icon": "Google Cloud.svg",
"cpe": "cpe:2.3:a:google:cloud_platform:*:*:*:*:*:*:*:*",
"source": "http"
},
{
"name": "Google Cloud CDN",
"categories": ["CDN"],
"confidence": 100,
"description": "Cloud CDN uses Google's global edge network to serve content closer to users.",
"website": "https://cloud.google.com/cdn",
"icon": "google-cloud-cdn.svg",
"source": "http"
},
{
"name": "Google Cloud Load Balancing",
"categories": ["Load balancers"],
"confidence": 100,
"description": "Google Cloud Load Balancing is a scalable, fully managed global load balancing service using Google Frontend.",
"website": "https://cloud.google.com/load-balancing",
"icon": "Google Cloud.svg",
"source": "http"
},
{
"name": "Google Cloud Trace",
"categories": ["Performance"],
"confidence": 100,
"description": "Google Cloud Trace is a distributed tracing system that collects latency data from applications and displays it in the Google Cloud Console.",
"website": "https://cloud.google.com/trace",
"icon": "google-cloud-trace.svg",
"source": "http"
},
{
"name": "Google Tag Manager",
"categories": ["Tag managers"],
"confidence": 100,
"source": "http"
},
{
"name": "HSTS",
"categories": ["Security"],
"confidence": 100,
"source": "http"
},
{
"name": "HTTP/3",
"categories": ["Miscellaneous"],
"confidence": 100,
"source": "http"
},
{
"name": "reCAPTCHA",
"categories": ["Security"],
"confidence": 100,
"source": "http"
}
],
"categories": {
"CDN": ["Google Cloud CDN"],
"IaaS": ["Google Cloud"],
"Load balancers": ["Google Cloud Load Balancing"],
"Miscellaneous": ["HTTP/3"],
"Performance": ["Google Cloud Trace"],
"Security": ["reCAPTCHA", "HSTS"],
"Tag managers": ["Google Tag Manager"]
},
"meta": {
"status_code": 200,
"tech_count": 8,
"scan_depth": "full"
},
"cached": false,
"response_ms": 456
}
Four of the eight entries are Google infrastructure, each from a different header: via gave Google Cloud CDN, server gave Google Cloud Load Balancing, x-cloud-trace-context gave Google Cloud Trace, and the implication chain gave Google Cloud under IaaS. The description, website, and icon fields for the last four technologies are trimmed above to keep the listing short; the API always returns them.
Single Domain: GET /analyze With Your RapidAPI Key
For production use, call /analyze through RapidAPI with your key. The response shape is identical to /demo, so the same jq filters work on both. This pulls out every CDN-category entry plus the implied cloud provider:
$ curl -s "https://detectzestack.p.rapidapi.com/analyze?url=www.snapchat.com" \
-H "X-RapidAPI-Key: YOUR_KEY" \
-H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" \
| jq '{domain, cdn: .categories.CDN, iaas: .categories.IaaS, tech_count: .meta.tech_count, cached, response_ms}'
{
"domain": "www.snapchat.com",
"cdn": ["Amazon S3", "Google Cloud CDN"],
"iaas": ["Google Cloud"],
"tech_count": 15,
"cached": false,
"response_ms": 884
}
Snapchat is a useful reminder that the CDN category is a list, not a single value. Amazon S3 appears beside Google Cloud CDN because the page loads assets from an S3 bucket while the HTML itself is served through Google’s edge. A prospecting filter should therefore test for membership (.categories.CDN | index("Google Cloud CDN")) rather than equality.
Two fields to read on every result. meta.scan_depth is "full" when the page body and headers were fetched and "partial" when only DNS resolved; a partial scan cannot see the Via header, so absence of Google Cloud CDN on a partial scan means unknown, not no. cached is true when the result was served from DetectZeStack’s cache; response_ms is the wall-clock time for this call.
Yes/No Check: GET /check?url=...&tech=Google%20Cloud%20CDN
When a single boolean is all you need, /check returns a smaller object. The technology name is matched case-insensitively and must be URL-encoded because it contains spaces:
$ curl -s "https://detectzestack.p.rapidapi.com/check?url=www.waze.com&tech=Google%20Cloud%20CDN" \
-H "X-RapidAPI-Key: YOUR_KEY" \
-H "X-RapidAPI-Host: detectzestack.p.rapidapi.com"
{
"domain": "www.waze.com",
"technology": "Google Cloud CDN",
"detected": true,
"confidence": 100,
"version": "",
"categories": ["CDN"],
"response_ms": 471,
"cached": false
}
The technology field echoes the canonical name from the database when there is a match, so tech=google%20cloud%20cdn in lowercase comes back as "Google Cloud CDN". A miss returns "detected": false with confidence 0 and an empty categories array.
Scan a List of Domains: POST /analyze/batch
POST /analyze/batch accepts up to 10 URLs per request and scans them concurrently. Each item in results carries either a result object in the single-domain shape or an error string:
$ curl -s -X POST "https://detectzestack.p.rapidapi.com/analyze/batch" \
-H "X-RapidAPI-Key: YOUR_KEY" \
-H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" \
-H "Content-Type: application/json" \
-d '{"urls": ["www.waze.com", "www.wix.com", "www.snapchat.com"]}' \
| jq '.results[] | {url, cdn: .result.categories.CDN, depth: .result.meta.scan_depth}'
{ "url": "www.waze.com", "cdn": ["Google Cloud CDN"], "depth": "full" }
{ "url": "www.wix.com", "cdn": ["Google Cloud CDN"], "depth": "full" }
{ "url": "www.snapchat.com", "cdn": ["Amazon S3", "Google Cloud CDN"], "depth": "full" }
The script below reads domains.txt, one domain per line, sends batches of 10, and writes one CSV row per domain with three columns that matter: whether the API reported Google Cloud CDN, the full CDN list, and the raw Via header from a direct HEAD request. The third column is what catches the multi-hop cases (1.1 google, 1.1 varnish) that the anchored fingerprint does not match. Partial scans go to a retry file instead of being recorded as negatives:
#!/usr/bin/env bash
# find-google-cloud-cdn.sh - flag domains served through Google's edge
KEY="YOUR_KEY"
HOST="detectzestack.p.rapidapi.com"
echo "domain,api_detected,cdn_list,raw_via,tech_count" > gcdn_audit.csv
: > gcdn_retry.txt
# Process domains.txt in batches of 10 (the /analyze/batch maximum)
xargs -n 10 < domains.txt | while read -r batch; do
urls=$(printf '%s\n' $batch | jq -R . | jq -s '{urls: .}')
resp=$(curl -s -X POST "https://$HOST/analyze/batch" \
-H "X-RapidAPI-Key: $KEY" \
-H "X-RapidAPI-Host: $HOST" \
-H "Content-Type: application/json" \
-d "$urls")
# One row per fully scanned domain
echo "$resp" | jq -r '.results[]
| select(.result != null and .result.meta.scan_depth == "full")
| .result as $r
| [
$r.domain,
((($r.categories.CDN // []) | index("Google Cloud CDN")) != null),
(($r.categories.CDN // []) | join(";")),
($r.meta.tech_count | tostring)
]
| @tsv' | while IFS=$'\t' read -r domain api_hit cdns count; do
# Second signal: the raw Via header, which also catches multi-hop values
raw_via=$(curl -sI --max-time 15 "https://$domain" \
| grep -i '^via:' | head -1 | cut -d' ' -f2- | tr -d '\r' | tr ',' ';')
echo "$domain,$api_hit,$cdns,$raw_via,$count" >> gcdn_audit.csv
done
# Unknown: no body or headers fetched, so absence proves nothing
echo "$resp" | jq -r '.results[]
| select(.result != null and .result.meta.scan_depth == "partial")
| .result.domain' >> gcdn_retry.txt
done
echo "scanned: $(($(wc -l < gcdn_audit.csv) - 1))"
echo "google edge: $(awk -F, 'NR>1 && ($2=="true" || $4 ~ /1\.1 google/)' gcdn_audit.csv | wc -l)"
echo "retries: $(wc -l < gcdn_retry.txt)"
A 1,000-domain list is 100 batch calls plus one HEAD request per domain. The API row gives you the CDN list and the rest of the stack for scoring; the raw Via column gives you the Spotify-style multi-hop sites. Domains where the API says false but the raw header contains 1.1 google are the ones worth a second look, because they are almost always Google’s edge with a Varnish or custom proxy tier behind it. Throughput, retry policy, and a production Python version of this loop are covered in how to batch scan 1,000 websites.
Google Cloud CDN vs Amazon CloudFront vs Fastly vs Cloudflare: Telling Them Apart by Header
All four land in the same CDN category in the API response, so a category filter catches any of them and a name filter isolates one. When you are reading raw headers, this is what distinguishes them. Every value in the Google, CloudFront, and Fastly rows was observed on a live site during testing:
| CDN | Via header | Other headers | DNS signal |
|---|---|---|---|
| Google Cloud CDN | via: 1.1 google | Server: Google Frontend, X-Cloud-Trace-Context (both optional) | None. Anycast IP, no Google suffix |
| Amazon CloudFront | via: 1.1 <id>.cloudfront.net (CloudFront) | X-Amz-Cf-Id, X-Amz-Cf-Pop, X-Cache: Hit from cloudfront | CNAME to *.cloudfront.net (common, not required) |
| Fastly | via: 1.1 varnish | X-Served-By: cache-*, X-Cache, Fastly-* headers | CNAME to *.fastly.net or *.fastlylb.net |
| Cloudflare | None by default | CF-Ray, CF-Cache-Status, Server: cloudflare | Nameservers *.ns.cloudflare.com |
Two traps. First, via: 1.1 varnish alone does not prove Fastly; self-hosted Varnish writes the same value, and Fastly is confirmed by the X-Served-By or Fastly-* headers, as explained in find companies using Fastly. Second, a multi-hop Via such as 1.1 google, 1.1 varnish means both tiers are real: Google’s edge in front, a Varnish cache behind it. Record both rather than picking one. CloudFront’s own signatures, including the X-Amz-Cf-Pop header that names the edge location, are broken down in find companies using Amazon CloudFront.
Get Your API Key on RapidAPI
The /demo endpoint is the fastest way to confirm the response shape against a domain you already know: no signup, 20 requests per hour, full JSON. For lists, audits, or anything you want to run again next quarter, the free RapidAPI plan includes 100 requests per month with no credit card. Paid plans start at $9 per month for 1,000 requests, and every plan includes header, DNS, and TLS detection on every scan, so Google Cloud CDN, CloudFront, Fastly, Cloudflare, and the rest of the stack all come back in the same call.
Try DetectZeStack Free
100 requests per month, no credit card required. Header, DNS, and TLS detection included on every plan.
Get Your Free API KeyConclusion
Google Cloud CDN is detected from one header: via: 1.1 google, written by Google’s global front end for traffic that passes through an external Application Load Balancer. Server: Google Frontend, X-Cloud-Trace-Context, and a Google Trust Services certificate corroborate it when present, and an Age header on a public response confirms the cache is actually doing work. DNS cannot confirm it, because the edge sits on a customer-specific anycast IP with no Google-owned hostname in the chain. For one domain, curl -sI answers the question in a second. For a list, the DetectZeStack API returns Google Cloud CDN under the CDN category, adds Google Cloud under IaaS by implication, and hands you the rest of the stack in the same response, with a raw Via check in the batch script to catch the multi-hop sites the anchored fingerprint skips.
Related Reading
- How to Detect if a Website Uses Google Cloud — The DNS and TLS signals for Cloud Run, App Engine, Cloud Functions, and Cloud Storage, the hosting products that sit behind or beside the CDN edge
- How to Detect the CDN and Hosting Provider of Any Website — The full multi-layer method across Cloudflare, CloudFront, Fastly, Akamai, and more
- Find Companies Using Amazon CloudFront — The X-Amz-Cf-* headers and cloudfront.net CNAME that make AWS’s edge the easiest CDN to spot
- Find Companies Using Fastly — Why via: 1.1 varnish needs the X-Served-By confirmation, and the fastly.net DNS signal
- How to Batch Scan 1,000 Websites for Tech Stack Data — Deep dive on /analyze/batch throughput, retries, and a Python scanner
- DNS and TLS Detection vs Browser Extensions — What a server-side scan sees that a browser extension does not, and vice versa