Find Companies Using Unpkg: Technographic API Guide

September 5, 2026 · 11 min read

Unpkg is the CDN that sits in the README of a large share of npm packages. If a package author wants to show a one-line “just drop this in a script tag” install path, the URL they paste is almost always https://unpkg.com/package@version/file. That habit has spread unpkg across a very specific slice of the web: docs sites, package demos, CodePen-style prototypes that graduated to a real domain, and internal tools built without a bundler. Finding the companies behind those sites is a narrow but useful technographic query.

This guide covers what unpkg actually is, how DetectZeStack fingerprints it from the page HTML, why it never surfaces in DNS or headers, how it compares to jsDelivr, cdnjs, and Google Hosted Libraries, and how to go from one curl command to a batch-built list of companies using unpkg. Every example uses the real API response shape.

What Unpkg Is and Why Companies Load Scripts From It

Unpkg is a free, public content delivery network for everything published to the npm registry. Any file inside any npm package is reachable at a predictable URL: unpkg.com/[email protected]/umd/react.production.min.js serves that exact file from that exact version. Leave off the version and unpkg redirects to the latest release. Leave off the file path and it picks the package's declared browser entry point. There is no account, no configuration, and nothing to deploy.

Companies end up loading from unpkg for a handful of recurring reasons:

Unpkg usage is a habit, not an infrastructure decision. It tells you how a team ships front-end code, not which CDN proxies their traffic.

How Unpkg Detection Works: the unpkg.com Fingerprint

Unpkg is a library-delivery CDN, so detection is a body-fingerprint match. When DetectZeStack fetches a page, it scans the served HTML for references to the unpkg host and reports a match as Unpkg under the CDN category, at confidence 100, with source: "http". The http source value means the evidence came from the HTTP response body rather than from DNS or the TLS certificate.

Script src and link href patterns the detector matches

The Unpkg fingerprint in the detection database has two parts, and either one is enough for a match:

PatternMatchesExample in the page
Script source unpkg.com/ <script src="https://unpkg.com/vue@3/dist/vue.global.js">
Link href link[href*='unpkg.com'] <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css">

The script pattern is a regular expression applied to every src attribute in the page; the trailing slash keeps it from matching unrelated hosts that merely contain the string. The link pattern is a DOM selector, so it catches stylesheets, preloads, and modulepreload hints that point at unpkg even when no script tag does. Both are evaluated against the HTML exactly as the server returned it.

You can reproduce the raw signal yourself in one line:

$ curl -s https://example.com | grep -o "unpkg\.com/[^\"']*" | head -3
unpkg.com/[email protected]/dist/vue.global.prod.js
unpkg.com/[email protected]/dist/leaflet.css

Why Unpkg Never Shows Up in DNS, Headers, or TLS

DetectZeStack runs four detection layers on every scan: HTTP body and headers, DNS records, and the TLS certificate. Infrastructure CDNs light up the last three. Cloudflare leaves a CNAME, a cf-ray header, and often a Cloudflare-issued certificate. Fastly and CloudFront leave equivalent marks. Those layers are covered in the guide on detecting the CDN and hosting provider of any website.

Unpkg touches none of them. A company does not put its own domain behind unpkg. The site's DNS still points at its real host, the site's response headers still come from its real server, and the certificate is still the site's own. The only trace of unpkg is inside the HTML, where a tag tells the browser to go fetch a file from unpkg.com. That is why an unpkg-only scan run against DNS and TLS alone would return nothing, and why meta.scan_depth matters when you read the results, which the batch section below comes back to.

The live scan of unpkg.com itself makes the layering visible. The demo response lists two entries under CDN: Cloudflare, which proxies the unpkg.com domain and is detected from headers, and Unpkg, which is detected because unpkg's own homepage loads assets from unpkg. Two CDN entries, two different layers, one page.

Unpkg vs jsDelivr vs cdnjs vs Google Hosted Libraries

All four are library-delivery CDNs, all four are detected from the page body, and all four land under the same CDN category. What differs is the catalog each one serves and the URL shape a page uses to reach it:

CDNHost in the pageWhat it serves
Unpkg unpkg.com Every file in every npm package, at package@version/path
jsDelivr cdn.jsdelivr.net npm, GitHub repositories, and WordPress plugins, with version aliasing and combined files
cdnjs cdnjs.cloudflare.com A curated catalog of popular libraries, versioned in the path
Google Hosted Libraries ajax.googleapis.com A short list of long-lived libraries such as jQuery and Dojo

cdnjs and Google Hosted Libraries reflect a curated, older set of libraries, and a page loading jQuery from ajax.googleapis.com is usually a page built some years ago. Unpkg and jsDelivr both mirror npm directly, so they show up wherever a team pulls a modern package without bundling it, and a site that references one often references the other. Companion guides cover finding companies using jsDelivr, detecting cdnjs, and finding companies using Google Hosted Libraries; the pipeline below works for any of them by changing one string.

Who Uses Unpkg: Frontend Prototypes, Docs Sites, and Package Demos

Because unpkg is the CDN of the npm README, its footprint clusters around a few kinds of sites:

API Example: Confirming Unpkg on One Domain with /analyze

The public demo endpoint needs no API key and is the quickest way to confirm a single domain. It is IP-rate-limited, so use it for spot checks rather than list building:

$ curl -s "https://detectzestack.com/demo?url=unpkg.com" \
  | jq '.technologies[] | select(.name == "Unpkg")'
{
  "name": "Unpkg",
  "categories": ["CDN"],
  "confidence": 100,
  "description": "Unpkg is a content delivery network for everything on npm.",
  "website": "https://unpkg.com",
  "icon": "Unpkg.png",
  "source": "http",
  "version": "",
  "cpe": ""
}

Note the capitalization: the technology name in the response is Unpkg with a capital U. Filters that compare against a lowercase unpkg return nothing, which is an easy mistake to make in a jq or Python pipeline. The version field is empty because unpkg is a delivery network, not a versioned library; versions belong to the packages it delivers.

With an API key, /analyze returns the full stack for a domain. Here is the shape of a complete response for a page that loads Vue from unpkg:

$ 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": "Unpkg",
      "categories": ["CDN"],
      "confidence": 100,
      "description": "Unpkg is a content delivery network for everything on npm.",
      "website": "https://unpkg.com",
      "icon": "Unpkg.png",
      "source": "http",
      "version": "",
      "cpe": ""
    },
    {
      "name": "Vue.js",
      "categories": ["JavaScript frameworks"],
      "confidence": 100,
      "description": "Vue.js is an open-source model–view–viewmodel JavaScript framework for building user interfaces and single-page applications.",
      "website": "https://vuejs.org",
      "icon": "vue.svg",
      "source": "http",
      "version": "3.4.21",
      "cpe": ""
    },
    {
      "name": "Netlify",
      "categories": ["PaaS", "CDN"],
      "confidence": 100,
      "description": "Netlify providers hosting and server-less backend services for web applications and static websites.",
      "website": "https://www.netlify.com/",
      "icon": "Netlify.svg",
      "source": "http",
      "version": "",
      "cpe": ""
    }
  ],
  "categories": {
    "CDN": ["Unpkg", "Netlify"],
    "JavaScript frameworks": ["Vue.js"],
    "PaaS": ["Netlify"]
  },
  "meta": { "status_code": 200, "tech_count": 3, "scan_depth": "full" },
  "cached": false,
  "response_ms": 1842
}

Reading the technologies array and the CDN category

Three entries from one page tell three different stories. Unpkg is the delivery method. Vue.js is the thing being delivered, with the version parsed from the [email protected] path segment. Netlify is the host, and it appears under CDN as well because Netlify fronts static sites with its own edge network. The top-level categories map groups the same detections by category, so .categories.CDN gives you every CDN on the page without walking the array. When both an infrastructure CDN and unpkg appear in that list, you are looking at two independent facts about the site, not a contradiction.

The meta object holds exactly three fields: the HTTP status_code, the tech_count, and the scan_depth. Timing lives at the top level in response_ms, and cached reports whether the result came from a recent identical scan.

Watch 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 the DNS and TLS layers completed. Unpkg lives in the body, so a missing Unpkg entry on a partial scan is an unknown, not a negative. Route those domains to a retry queue.

Building a Companies-Using-Unpkg List with /analyze/batch

POST /analyze/batch accepts up to 10 URLs per request and scans them concurrently. Each item in the response carries either a full result object in the single-domain shape or an error string for a domain 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": ["unpkg.com", "example.com", "example.org"]}'
{
  "results": [
    { "url": "unpkg.com",   "result": { "...full analysis...": "" } },
    { "url": "example.com", "result": { "...full analysis...": "" } },
    { "url": "example.org", "result": { "...full analysis...": "" } }
  ],
  "total_ms": 2341,
  "successful": 3,
  "failed": 0
}

Filtering batch results for the Unpkg entry

Because every result matches the single-domain shape, the same jq filter works for one domain or a thousand. The script below reads domains.txt, one domain per line, sends batches of 10, and appends every unpkg-confirmed domain to a CSV along with the packages unpkg is delivering, the scan depth, and the tech count. Domains that came back partial are written to a separate retry file rather than silently dropped:

#!/usr/bin/env bash
# find-unpkg.sh - filter a domain list down to unpkg-confirmed leads
KEY="YOUR_KEY"
HOST="detectzestack.p.rapidapi.com"

echo "domain,delivered_libraries,tech_count" > unpkg_leads.csv
: > unpkg_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")

  # Confirmed: Unpkg present in the technologies array
  echo "$resp" | jq -r '.results[]
    | select(.result != null)
    | .result as $r
    | select([$r.technologies[].name] | index("Unpkg"))
    | [
        $r.domain,
        ([$r.technologies[]
          | select(.name != "Unpkg" and (.categories | index("CDN") | not))
          | .name] | join(";")),
        ($r.meta.tech_count | tostring)
      ]
    | @csv' >> unpkg_leads.csv

  # Unknown: body fetch failed, so absence of Unpkg proves nothing
  echo "$resp" | jq -r '.results[]
    | select(.result != null)
    | select(.result.meta.scan_depth == "partial")
    | .result.domain' >> unpkg_retry.txt
done

echo "leads:   $(($(wc -l < unpkg_leads.csv) - 1))"
echo "retries: $(wc -l < unpkg_retry.txt)"

A 1,000-domain list becomes 100 batch calls. The index("Unpkg") guard keeps a domain whenever Unpkg appears in its technology list. The second column collects every non-CDN detection on the page, which for an unpkg site is usually the library being delivered plus whatever else the page runs. The select(.result != null) guard skips domains that failed to resolve, since those come back with an error field instead of a result. For throughput, retry strategy, and a production Python scanner, see how to batch scan 1,000 websites.

To segment by delivered library instead of by delivery method, replace the index("Unpkg") check with a two-part condition, for example Unpkg present and Vue.js present. That yields a list of companies loading Vue from unpkg specifically, which is a sharper audience than either signal alone.

Comparing Unpkg Adoption Across Competitors with /compare

POST /compare takes 2 to 10 URLs and returns each domain's full technologies array, a shared list of technologies present on every domain, and a per-domain unique list. It is the right call when the question is not “who uses unpkg” but “how do these specific competitors ship front-end code”:

$ curl -s -X POST "https://detectzestack.p.rapidapi.com/compare" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["unpkg.com", "example.com", "example.org"]}' \
  | jq -r '.domains[]
      | [.domain,
         ([.technologies[] | select(.categories | index("CDN")) | .name] | join(";"))]
      | @tsv'
unpkg.com     Cloudflare;Unpkg
example.com   Unpkg;Netlify
example.org   Cloudflare

Each line is a domain followed by every CDN it uses, which puts the infrastructure CDN and the library-delivery CDN side by side. A competitor set where one company shows Unpkg and the others show only Cloudflare or CloudFront is a set where one company ships without a bundler and the rest do not. Each URL in the request counts as one request against your plan, the same as a batch call.

What an Unpkg Signal Tells a Sales or Security Team

An unpkg detection is rarely the end of the query. It is the entry point to a segment, and the segment depends on who is asking.

Limits: No Global Index, Version Pinning, and Self-Hosted Fallbacks

Three limits are worth stating plainly so the list you build means what you think it means.

There is no global index of unpkg users. DetectZeStack scans the domains you give it. It does not maintain a crawled database of every site on the web, so “find companies using unpkg” in practice means “filter my domain list down to the ones using unpkg.” Bring the list from your CRM, a directory, or a competitor set; the API confirms the signal per domain.

Version pinning affects what you learn, not whether Unpkg is detected. A pinned URL such as unpkg.com/[email protected]/... and an unpinned one such as unpkg.com/vue@3/... both match the fingerprint. The difference is that a pinned URL gives the delivered library a precise version, while an unpinned one may leave the version empty or resolve to a major-only value. If version matters for your segmentation, keep the raw script URL from the grep step as well as the API's parsed field.

Self-hosted fallbacks and late-injected scripts can hide the reference. Some pages load a library from their own domain and reference unpkg only in a fallback branch inside inline JavaScript, or add the unpkg tag from client-side code after load. Detection reads the HTML as served, so a reference that only exists after JavaScript runs may not appear. Conversely, a site that vendors every library will show the library, for example Bootstrap from /static/js/bootstrap.min.js, with no Unpkg entry at all. A missing Unpkg detection means the served page does not reference unpkg. It does not mean the company never touches npm.

Conclusion and Getting an API Key

Finding companies using unpkg reduces to reading one signal well: a script src containing unpkg.com/ or a link href containing unpkg.com in the served HTML. Because unpkg is a library-delivery CDN rather than an infrastructure one, it appears only in the page body, never in DNS, headers, or TLS, and it commonly sits beside an infrastructure CDN in the same CDN category. A single /analyze call answers the one-domain question, /analyze/batch turns a domain list into an unpkg-confirmed lead list with the delivered libraries alongside, /compare lines up a competitor set, and meta.scan_depth tells you which negatives are real.

The free tier includes 100 requests per month with no credit card, which is enough to validate the pipeline on a sample before scaling up:

  1. Get your free API key at rapidapi.com/mlugoapx/api/detectzestack.
  2. Spot-check a domain you know: curl -s "https://detectzestack.com/demo?url=yourdomain.com" | jq '.categories.CDN'
  3. Run the batch script above against your first 100 domains and read the retry file before you read the leads file.

Related Reading

Try DetectZeStack Free

100 requests per month, no credit card required. Header, DNS, and TLS detection included on every plan.

Get Your Free API Key

Get API updates and tech detection tips

Join the mailing list. No spam, unsubscribe anytime.