cdnjs is one of the most widely used free public CDNs on the web. It is a community-run, open-source library-delivery service hosted on Cloudflare's network, and it lets a developer drop a single <script> tag into a page to pull in jQuery, Font Awesome, Lodash, or almost any popular open-source package without hosting a file. That convenience is exactly why “loads assets from cdnjs” is a useful detection signal: it tells you something concrete about how a team builds and ships its front end.
This guide walks through detecting cdnjs on a website—what it actually is, where it shows up in a page's source, how to spot it manually, and how a single DetectZeStack API call returns cdnjs along with the specific libraries and versions it is delivering. We will start with a one-line check you can run right now.
What Is cdnjs and Why Detect It
cdnjs (short for “CDN for JavaScript”) is a free, open-source content delivery service that mirrors thousands of popular front-end libraries and serves them from the cdnjs.cloudflare.com hostname. Where an infrastructure CDN like Cloudflare or Amazon CloudFront proxies a whole site's traffic, cdnjs does something narrower: it hands out versioned copies of other people's open-source code so a page does not have to bundle and self-host them.
A confirmed cdnjs reference is a small but specific window into a team's front-end habits:
-
They lean on public CDNs for dependencies. Loading libraries from
cdnjs.cloudflare.comrather than bundling and self-hosting them is a deliberate choice. It often signals a leaner build setup—static sites, server-rendered pages, or templates where a script tag is faster than running a bundler. - It usually arrives with the library it delivers. cdnjs rarely travels alone. The same page that references it is almost always loading a detectable library—jQuery, Font Awesome, a charting or animation library—so one detection often hands you a slice of the front-end stack as well.
- It hints at a supply-chain posture. Teams that pull live third-party scripts from a public CDN have a different dependency surface than teams that vendor everything. For security tooling, software-composition-analysis, or subresource-integrity products, that distinction is the qualifier.
The same detection pipeline applies to any technology DetectZeStack recognizes. We have companion guides for the sibling library-delivery CDN jsDelivr and for Google Hosted Libraries—the fingerprint changes, the workflow stays the same.
How cdnjs Shows Up in a Website's Source
cdnjs is a library-delivery CDN. It exists to serve versioned, open-source assets—a specific build of jQuery, a pinned release of Font Awesome, a particular Lodash version—straight from Cloudflare-hosted mirrors. A company does not put its own domain behind cdnjs; it references cdnjs from inside its pages to fetch other people's code.
That has a direct consequence for detection. Finding cdnjs on a site does not tell you who hosts the site or how its traffic is proxied. It tells you the page intentionally pulls at least one third-party asset from cdnjs, and it points you at which asset when that asset is itself fingerprintable.
Script tags pointing to cdnjs.cloudflare.com
Every cdnjs reference resolves to the same hostname. In the page source it looks like an ordinary script or stylesheet link:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
The constant across all of them is the cdnjs.cloudflare.com host. That single string is the primary fingerprint: if it appears in a script src or a link href in the served HTML, the page references cdnjs. It is also why cdnjs implies Cloudflare—the service is hosted on Cloudflare's network, so a cdnjs match means the page is pulling code from a Cloudflare-hosted origin, distinct from the whole site being proxied through Cloudflare.
Library and version fingerprints cdnjs leaves behind
cdnjs URLs are unusually informative because the path is structured: /ajax/libs/<library>/<version>/<file>. The example above encodes the library (jquery) and the exact version (3.6.0) right in the URL. That structure means two things show up in a single page fetch—the delivery method (cdnjs) and the delivered library, frequently with its version parsed straight from the path.
| Signal | Example | What It Tells You |
|---|---|---|
| cdnjs host reference | cdnjs.cloudflare.com | cdnjs confirmed (CDN) |
| Delivered library + version | .../ajax/libs/jquery/3.6.0/jquery.min.js | jQuery confirmed, version parsed |
| Self-hosted library | /static/js/jquery.min.js | Library detected, no cdnjs signal |
| No cdnjs reference | (none in HTML) | Page does not load assets from cdnjs |
Manual Ways to Detect cdnjs (and Their Limits)
Because cdnjs lives in the page body, you can spot the raw signal yourself without any tooling. The fastest check is a single curl piped into grep:
$ curl -s https://example.com | grep -o "cdnjs\.cloudflare\.com" | head -1
cdnjs.cloudflare.com
One match is enough to confirm the page references cdnjs. To see exactly what it is pulling, widen the pattern to capture the full URLs and read the library and version out of each path:
$ curl -s https://example.com \
| grep -oE "cdnjs\.cloudflare\.com/ajax/libs/[^\"']+" | sort -u
cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css
This works, but it has real limits when you move past one site. The reference only appears if it is present in the server-rendered HTML—a script injected later by client-side JavaScript, or one loaded through a tag manager, may not show up in a plain curl. You also have to parse each path yourself to turn it into structured data, and running this across hundreds of domains means writing your own concurrency, retry, and timeout handling. That is the gap a detection API closes: it normalizes the same body signal into clean JSON and runs it at scale.
Detect cdnjs Programmatically with the DetectZeStack API
When DetectZeStack fetches a page, it scans the HTML for script and link references to cdnjs.cloudflare.com. A match returns cdnjs under the CDN category at confidence 100, with source: "http"—because the evidence came directly from the HTTP response body.
You can try it right now against the public demo endpoint—no API key required. The demo is IP-rate-limited, so use it for spot checks rather than bulk scans:
$ curl -s "https://detectzestack.com/demo?url=example.com" \
| jq '.technologies[] | select(.name == "cdnjs")'
{
"name": "cdnjs",
"categories": ["CDN"],
"confidence": 100,
"description": "cdnjs is a free distributed JS library delivery service.",
"website": "https://cdnjs.com",
"icon": "cdnjs.svg",
"source": "http",
"version": "",
"cpe": ""
}
cdnjs is matched directly off the cdnjs.cloudflare.com reference in the page and categorized under CDN. It carries source: "http" because the evidence came from the HTTP response body, and the version field is empty—cdnjs itself is a delivery network, not a versioned library, so there is nothing to read a version from. The libraries it delivers are where versions show up.
Reading the technologies, version, and categories fields
When you want the full stack for a domain rather than a filtered slice, call /analyze with your API key. A page that loads jQuery from cdnjs comes back like this:
$ curl -s "https://detectzestack.p.rapidapi.com/analyze?url=example.com" \
-H "X-RapidAPI-Key: YOUR_KEY" \
-H "X-RapidAPI-Host: detectzestack.p.rapidapi.com"
{
"url": "https://example.com",
"domain": "example.com",
"technologies": [
{
"name": "cdnjs",
"categories": ["CDN"],
"confidence": 100,
"description": "cdnjs is a free distributed JS library delivery service.",
"website": "https://cdnjs.com",
"icon": "cdnjs.svg",
"source": "http",
"version": "",
"cpe": ""
},
{
"name": "jQuery",
"categories": ["JavaScript libraries"],
"confidence": 100,
"description": "jQuery is a JavaScript library designed to simplify HTML DOM tree traversal and manipulation, as well as event handling, CSS animation, and Ajax.",
"website": "https://jquery.com",
"icon": "jQuery.svg",
"source": "http",
"version": "3.6.0",
"cpe": ""
},
{
"name": "Cloudflare",
"categories": ["CDN"],
"confidence": 100,
"description": "Cloudflare is a web-infrastructure and website-security company that provides content-delivery-network services, DDoS mitigation, and ICANN-accredited domain registration services.",
"website": "https://www.cloudflare.com",
"icon": "CloudFlare.svg",
"source": "http",
"version": "",
"cpe": ""
}
],
"categories": {
"CDN": ["cdnjs", "Cloudflare"],
"JavaScript libraries": ["jQuery"]
},
"meta": { "status_code": 200, "tech_count": 3, "scan_depth": "full" },
"cached": false,
"response_ms": 1842
}
Three entries from one page. cdnjs is the delivery method; jQuery is the thing being delivered, with its version parsed from the script URL; and Cloudflare appears because cdnjs is hosted on Cloudflare's network and its fingerprint implies Cloudflare. The top-level categories map groups every detection, so you can pull all CDNs with .categories["CDN"] without iterating the array. The meta object carries the HTTP status_code, the tech_count, and the scan_depth; response_ms and cached sit at the top level.
One field to watch for list building is meta.scan_depth. A value of "full" means the HTTP fetch succeeded and body detection ran. A value of "partial" means the site blocked or timed out the HTTP request and only DNS and TLS layers completed—and since cdnjs lives in the body, an absent cdnjs entry on a "partial" scan tells you nothing. Those domains belong in a retry queue, not your rejects file.
The honest limitation: cdnjs detection depends on the HTML actually containing the reference. If a script is injected later by client-side JavaScript that never runs during a server-side fetch, or if the reference sits behind a tag manager, it may not appear in the fetched body. As with any body-fingerprint signal, absence of a detection is an unknown, not proof the site never touches cdnjs.
Detecting cdnjs Across Many Sites at Scale
For list building, POST /analyze/batch accepts up to 10 URLs per request and analyzes them concurrently. Each entry in the response carries either a full analysis result or an error for domains that could not be fetched:
$ 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": ["example.com", "getbootstrap.com", "wordpress.org"]}'
The response wraps one result object per URL, each with the same shape as a single /analyze response:
{
"results": [
{ "url": "example.com", "result": { "...full analysis..." : "" } },
{ "url": "getbootstrap.com", "result": { "...full analysis..." : "" } },
{ "url": "wordpress.org", "result": { "...full analysis..." : "" } }
],
"total_ms": 2341,
"successful": 3,
"failed": 0
}
Because each result matches the single-domain shape, the filtering logic is identical whether you scan one domain or a thousand. Here is a complete, copy-pasteable pipeline using nothing but bash, curl, and jq. It reads domains.txt (one domain per line), sends batches of 10 to /analyze/batch, and appends every domain where cdnjs is detected to cdnjs_leads.csv, recording the tech count alongside it:
#!/usr/bin/env bash
# find-cdnjs.sh — filter a domain list down to cdnjs-confirmed sites
KEY="YOUR_KEY"
HOST="detectzestack.p.rapidapi.com"
echo "domain,tech_count" > cdnjs_leads.csv
# 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: .}')
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" |
jq -r '.results[]
| select(.result != null)
| .result as $r
| select([$r.technologies[].name] | index("cdnjs"))
| [$r.domain, ($r.meta.tech_count | tostring)]
| @csv' >> cdnjs_leads.csv
done
wc -l cdnjs_leads.csv
A 1,000-domain list becomes 100 batch calls. The index("cdnjs") guard keeps a domain whenever cdnjs appears in its technology list, and select(.result != null) skips domains that failed to resolve (those come back with an error field instead of a result). For a deeper treatment of batch throughput, retries, and a production Python scanner, see how to batch scan 1,000 websites.
If you want to segment by the library cdnjs is delivering rather than just the delivery method, widen the filter to capture the co-detected technologies—the same technologies array already carries jQuery, Font Awesome, and whatever else the page pulls in. Our guides on detecting jQuery and the broader JavaScript framework detection cover those fingerprints in detail.
cdnjs vs Other JavaScript CDNs
“CDN” is an overloaded word, and it helps to be precise about where cdnjs sits. There are two very different things both called CDNs:
| Type | Examples | Detected From |
|---|---|---|
| Infrastructure CDN | Cloudflare, Fastly, Amazon CloudFront, Akamai | DNS CNAME, response headers, TLS certificate |
| Library-delivery CDN | cdnjs, jsDelivr, unpkg, Google Hosted Libraries | Script & link references in the page HTML |
An infrastructure CDN proxies the whole site, so it shows up in the site's DNS, headers, and certificate—the layer covered in how to detect a website's CDN and hosting provider and, for one specific provider, finding companies using Amazon CloudFront. cdnjs sits in the other column: it is detected purely from references inside the served HTML, alongside its peers jsDelivr (cdn.jsdelivr.net), unpkg (unpkg.com), and Google Hosted Libraries (ajax.googleapis.com).
cdnjs is closest to jsDelivr—both serve open-source libraries from a public mirror—with one wrinkle: cdnjs is hosted on Cloudflare, so its detection implies Cloudflare, while jsDelivr is independent. The flip side of both is the self-hosted case. A team that runs a bundler and ships its libraries from its own domain will load, say, jQuery from /static/js/jquery.min.js—no cdnjs reference at all. The library is still detectable on its own fingerprint, but the delivery signal is absent. A missing cdnjs detection does not mean the site avoids jQuery; it means the site does not fetch jQuery from cdnjs. Keep that distinction in mind when you read negatives.
Get Your API Key and Start Detecting cdnjs
The free tier includes 100 requests per month with no credit card—enough to validate the pipeline on a sample of your domain list before scaling up. Sign-up is instant through RapidAPI:
- Get a key at rapidapi.com/mlugoapx/api/detectzestack.
- Spot-check a domain you know:
curl -s "https://detectzestack.com/demo?url=yourdomain.com" | jq '.technologies[].name' - Run the batch script above against your first 100 domains.
Conclusion
Detecting cdnjs comes down to reading one thing well: a cdnjs.cloudflare.com reference in the page HTML. Because cdnjs is a library-delivery CDN rather than an infrastructure one, it is detected from the body, not from DNS or headers—and the real prize is usually the library it carries, whose name and version are encoded right in the URL path and returned alongside it. A single /analyze call answers the one-domain question; /analyze/batch turns a raw domain list into a cdnjs-confirmed list; and meta.scan_depth tells you which negatives are real and which are unknowns worth a retry. Swap the jq filter and the same pipeline segments by front-end library, infrastructure CDN, or backend runtime instead.
Related Reading
- Find Companies Using jsDelivr — The sibling library-delivery CDN (cdn.jsdelivr.net), detected from the page HTML the same way
- Find Companies Using Google Hosted Libraries — The other major library-delivery CDN (ajax.googleapis.com), with the delivered library and version encoded in the URL path
- How to Detect the CDN and Hosting Provider of Any Website — The infrastructure-CDN layer that sits in front of a site, detected via DNS, headers, and TLS
- How to Detect jQuery on a Website — One of the most common libraries delivered over cdnjs, and its own fingerprints
- Find Companies Using Amazon CloudFront — An infrastructure CDN detected from headers, DNS, and TLS instead of the page body
- How to Batch Scan 1,000 Websites for Tech Stack Data — Deep dive on /analyze/batch throughput, retries, and a Python scanner
- Lead Enrichment Pipeline with Tech Detection — Turning raw detections into scored, routable leads
Top comments (0)