Find Companies Using Modernizr: Detection API Guide
Modernizr is one of those libraries nobody adds to a new project anymore and nobody gets around to removing from an old one. That makes it a useful signal. A site still serving modernizr.js has a front end that was set up in the era when feature detection had to be done in JavaScript, and it has probably not been rebuilt since. Python.org, NPR, and Clojure.org all still load it today.
This guide covers how to spot Modernizr on a single site by hand, exactly how DetectZeStack detects it (and where that detection has gaps), and how to turn a domain list into a list of companies using Modernizr with a few API calls. Every API response and script path quoted below came from a real request made while writing this post.
What Modernizr Is and Why It Still Shows Up on Production Sites
Modernizr is a small JavaScript library that tests which HTML5 and CSS3 features the current browser supports. It records the answers in two places: a global Modernizr object (Modernizr.flexbox, Modernizr.svg, and so on), and a set of CSS classes on the <html> element, such as flexbox or no-flexbox. Stylesheets and scripts then branch on those results.
Feature Detection vs. User-Agent Sniffing, and Why Modernizr Mattered
Before feature detection, the usual way to decide whether a browser could handle something was to read its user-agent string and guess. That broke every time a browser shipped a new version or lied about its identity. Modernizr made the better approach easy: ask the browser directly whether a feature works, then load a polyfill or a fallback style only if it does not. It shipped as part of the HTML5 Boilerplate starter template, which is a large part of why it ended up on so many sites built in the early 2010s.
What a Modernizr Install Tells You About a Site's Front-End Age
Today's evergreen browsers support nearly everything Modernizr was built to test, so a fresh project rarely needs it. When you find it on a production site, it usually means one of three things:
- The site's template or theme dates from the HTML5 Boilerplate era and has been maintained rather than rebuilt.
- A CMS theme or agency starter kit bundled it by default, and it has stayed in the page ever since.
- Some CSS still branches on Modernizr classes, so removing it is not a one-line change.
The file itself often says how old it is. The script python.org serves at /static/js/libs/modernizr.js opens with this banner:
/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
* Build: http://modernizr.com/download/#-fontface-generatedcontent-input-inputtypes-geolocation-svg-touch-shiv-cssclasses-...
Modernizr 2.6.2 is a 2.x build from the early 2010s. That one comment tells you roughly when this front end was put together.
Who Looks for Companies Using Modernizr
Agencies Selling Front-End Modernization and Redesigns
A Modernizr hit is one of the cleaner "this site is due for a rebuild" signals you can get from outside. Paired with an old jQuery version in the same response, it gives an agency a concrete opening: here is what your site loads, here is when it dates from, here is what a modern build would remove.
Sales Teams Qualifying Leads by Legacy JavaScript Stack
If you sell performance tooling, front-end migration services, accessibility audits, or a headless CMS, a legacy JavaScript stack is a qualification filter. Modernizr works well as one because it is almost never added to new builds, so its presence tracks front-end age more reliably than jQuery does.
Competitive and Market Researchers
Researchers use library detection to measure how fast a segment modernizes: what share of a vertical still ships Modernizr, which of those also run jQuery 1.x, and how that changes quarter over quarter.
How to Detect Modernizr Manually
Check the Page Source for a modernizr.js Script Tag
The fastest check needs no browser. Fetch the HTML and grep for the filename. Use --compressed, because some servers (python.org is one) return gzip even to a plain curl, and grepping compressed bytes finds nothing:
curl -s --compressed https://www.python.org/ | grep -io '[^"]*modernizr[^"]*'
That prints /static/js/libs/modernizr.js. The same command against NPR prints a path ending in /lib/modernizr/modernizr.custom.js, and against Clojure.org prints /js/modernizr.js. To read the version, fetch the script and look at its first line:
curl -s --compressed https://www.python.org/static/js/libs/modernizr.js | head -c 200
Check the Browser Console for the Modernizr Global and Modernizr._version
In DevTools, the global object settles the question and usually gives the version too:
(function () {
var m = window.Modernizr;
console.log({
loaded: typeof m === 'object' || typeof m === 'function',
version: m && m._version,
htmlClasses: document.documentElement.className.split(/\s+/).length
});
})();
This check also finds Modernizr when it is bundled into an application file, because it runs inside the page instead of reading the HTML. That matters later: it is the one case the API cannot see.
Look for Feature Classes Added to the html Element
Modernizr adds a class for each test it runs. Inspect the <html> element in the Elements panel (not view-source, since the classes are added at runtime) and you will see a long list like js flexbox canvas svg no-touchevents. The raw HTML often carries class="no-js", which Modernizr swaps for js when it runs. Treat no-js as a hint only. It is an HTML5 Boilerplate convention that many sites keep without loading Modernizr at all.
How DetectZeStack Detects Modernizr
DetectZeStack's HTTP detection uses the open-source Wappalyzer fingerprint set. Its Modernizr entry declares two signals, and only one of them can fire in an HTTP scan:
| Signal type | What it looks for | Usable from an HTTP fetch? |
|---|---|---|
| js | Modernizr._version | No — needs a JavaScript runtime |
| scriptSrc | a <script src> path containing /modernizr and ending in .js | Yes |
DetectZeStack fetches the HTML and parses it. It does not run a headless browser or execute page JavaScript, so every Modernizr detection from the API comes from a script tag path. The match is case-insensitive and works with self-hosted files, CDN files, custom builds like modernizr.custom.js, and minified builds.
Script Source Filename Matching and Version Extraction from the Path
The version comes from the URL only, and the pattern is narrower than you might expect. We ran these paths through the same fingerprint library the API uses:
| Script path | Detected? | Version reported |
|---|---|---|
| /js/modernizr.js | yes | empty |
| /js/modernizr.2.8.3.min.js | yes | 2.8.3. (note the trailing dot) |
| /js/vendor/modernizr-2.8.3.min.js | yes | empty — the hyphen is not parsed |
| cdnjs .../ajax/libs/modernizr/2.8.3/modernizr.min.js | yes | empty — the earlier /modernizr directory matches first |
| .../modernizr.custom.js?ver=2.6.2 | yes | empty — query strings are ignored for this rule |
| /media/1089/modernizr.js | yes | 1089 — a media folder ID, not a version |
Two takeaways. First, an empty version is normal. Of the 135 domains where DetectZeStack's index had recorded Modernizr as of this writing, 134 had no version. Second, the one that did have a version had a wrong one. The rule treats any numeric directory right before /modernizr as a version, and some CMSs put files in numbered media folders. Clearmatch.com serves /media/1089/modernizr.js, and the API reports "version": "1089". Slick on the same site reports 1166 for the same reason. If you filter by version, drop anything that does not look like 2.x or 3.x, and strip trailing dots.
Limits: Renamed or Bundled Builds Without a modernizr Filename
If the path has no modernizr in it, there is nothing to match. A Modernizr build compiled into /assets/app.4f2c1a.js by webpack, or saved as feature-detects.js, is invisible to an HTTP scan. We confirmed both paths produce no detection. The sites that bundle Modernizr are usually the ones with a newer build pipeline, so the API's Modernizr list leans toward exactly the legacy sites a prospecting list is after. Even so, read a missing entry as "no matching script tag," not as proof the library is absent.
API Example: Detect Modernizr with a curl Request
Single Domain Check with GET /analyze
For production use, call /analyze with your RapidAPI key and pull out the Modernizr entry with jq:
curl -s "https://detectzestack.p.rapidapi.com/analyze?url=https://www.python.org" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com" \
| jq '.technologies[] | select(.name == "Modernizr")'
If Modernizr is not detected, jq prints nothing and exits cleanly, which makes this easy to drop into a shell loop. If you only need a yes or no, /check returns a flat object with detected, confidence, and version:
curl -s "https://detectzestack.p.rapidapi.com/check?tech=Modernizr&url=https://www.python.org" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com"
Reading the technologies Array: name, version, categories (JavaScript libraries)
Here is the live response for python.org, trimmed to the JavaScript libraries, with the categories map and the meta block left intact:
{
"url": "https://www.python.org",
"domain": "www.python.org",
"technologies": [
{
"name": "Modernizr",
"categories": ["JavaScript libraries"],
"confidence": 100,
"description": "Modernizr is a JavaScript library that detects the features available in a user's browser.",
"website": "https://modernizr.com",
"icon": "Modernizr.svg",
"source": "http"
},
{
"name": "jQuery",
"version": "1.8.2",
"categories": ["JavaScript libraries"],
"confidence": 100,
"description": "jQuery is a JavaScript library which is a free, open-source software 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",
"cpe": "cpe:2.3:a:jquery:jquery:*:*:*:*:*:*:*:*",
"source": "http"
}
],
"categories": {
"JavaScript libraries": ["jQuery", "jQuery UI", "Modernizr"]
},
"meta": { "status_code": 200, "tech_count": 10, "scan_depth": "full" },
"cached": false,
"response_ms": 555
}
What to take from it:
nameis exactlyModernizr, with a capital M. Filter on that string.categoriesis["JavaScript libraries"], so Modernizr also appears in the top-levelcategoriesmap under that key.- The
versionfield is missing. It is omitted when empty, because the path/static/js/libs/modernizr.jshas no version in it, even though the file's banner says 2.6.2. Injq, use.version // ""to handle both cases. sourceishttp: the detection came from the fetched HTML.- jQuery 1.8.2 shows up in the same response. Modernizr and old jQuery together are the usual legacy pairing.
Try It Without a Key Using GET /demo
The public /demo endpoint runs the same detection with no API key. It is rate-limited by IP, but it is enough to check the response shape before you write any code:
curl -s "https://detectzestack.com/demo?url=https://www.python.org" | python3 -m json.tool
Try it on https://clojure.org or https://www.npr.org too. Both returned a Modernizr entry with no version when we checked.
Building a List of Companies Using Modernizr at Scale
There are two ways to build the list: start from the index, or start from your own domains. Most teams do both.
To start from the index, use /lookup. It returns domains where Modernizr has already been detected, with first_seen and last_seen timestamps. How many results you get per page depends on your plan:
curl -s "https://detectzestack.p.rapidapi.com/lookup?tech=Modernizr&limit=50" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com" \
| jq -r '.results[].domain'
Scanning a Prospect List with POST /analyze/batch
To check your own list, such as a CRM export or a conference attendee list, send up to 10 URLs per request to /analyze/batch. Each URL counts as one request against your quota:
curl -s -X POST "https://detectzestack.p.rapidapi.com/analyze/batch" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://www.python.org", "https://www.npr.org", "https://clojure.org"]}' \
| jq -c '.results[] | {url: .url, modernizr: ([.result.technologies[]? | select(.name == "Modernizr")] | length > 0)}'
In a batch response, each item nests its analysis under .result (or has an error string instead). The top level also carries total_ms, successful, and failed. With those three domains, based on the single-domain scans above, the filter prints:
{"url":"https://www.python.org","modernizr":true}
{"url":"https://www.npr.org","modernizr":true}
{"url":"https://clojure.org","modernizr":true}
For lists longer than 10, send them in chunks. Batch Scan 1,000 Websites for Tech Stack covers concurrency, retries, and quota planning.
Comparing Competitor Front Ends with POST /compare
If you want to see which competitors still run Modernizr, not scan a whole list, /compare takes 2 to 10 URLs and returns each domain's technologies, a unique list per domain, and a top-level shared list:
curl -s -X POST "https://detectzestack.p.rapidapi.com/compare" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://www.python.org", "https://clojure.org"]}' \
| jq '{shared: .shared, unique: [.domains[] | {domain, unique}]}'
If Modernizr appears in shared, every site you compared loads it. If it appears in only one domain's unique list, that competitor is the one still carrying it.
Filtering Results by Version and Exporting to a CRM
This script reads domains from domains.txt, scans them in batches of 10, and writes a CSV with the Modernizr version and the jQuery version from the same scan. It applies the version check from earlier, so media-folder IDs like 1089 are dropped and trailing dots are stripped:
import csv, json, os, re, urllib.request
KEY = os.environ["RAPIDAPI_KEY"]
URL = "https://detectzestack.p.rapidapi.com/analyze/batch"
def clean(v):
v = (v or "").rstrip(".")
return v if re.match(r"^[23]\.\d+", v) else ""
domains = [d.strip() for d in open("domains.txt") if d.strip()]
rows = []
for i in range(0, len(domains), 10):
chunk = ["https://" + d if not d.startswith("http") else d for d in domains[i:i+10]]
req = urllib.request.Request(URL, data=json.dumps({"urls": chunk}).encode(), headers={
"x-rapidapi-key": KEY,
"x-rapidapi-host": "detectzestack.p.rapidapi.com",
"Content-Type": "application/json",
})
with urllib.request.urlopen(req, timeout=120) as resp:
data = json.load(resp)
for item in data["results"]:
techs = {t["name"]: t for t in (item.get("result") or {}).get("technologies", [])}
if "Modernizr" in techs:
rows.append({
"url": item["url"],
"modernizr_version": clean(techs["Modernizr"].get("version")),
"jquery_version": techs.get("jQuery", {}).get("version", ""),
"tech_count": len(techs),
})
with open("modernizr_prospects.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=["url", "modernizr_version", "jquery_version", "tech_count"])
w.writeheader()
w.writerows(rows)
print(f"{len(rows)} of {len(domains)} domains load Modernizr")
The CSV imports straight into HubSpot, Salesforce, or a spreadsheet. For a full enrichment flow, see Build a Lead Enrichment Pipeline with Tech Detection.
Modernizr Alongside jQuery, Bootstrap, and Other Legacy Libraries
Because /analyze returns the whole stack in one response, you get the libraries next to Modernizr for free, and they often tell you more than Modernizr does alone. From the live scans for this post:
- python.org: Modernizr, jQuery 1.8.2, jQuery UI 1.12.1, Google Hosted Libraries, Nginx, Varnish, and Fastly.
- clojure.org: Modernizr, jQuery 1.11.1, and Google Hosted Libraries, on Webflow behind Amazon CloudFront.
- clearmatch.com: Modernizr, jQuery 2.1.4, Slick, Stellar.js, and ZURB Foundation.
- poynter.org: Modernizr on WordPress, with Bootstrap 5.3.3, jQuery Migrate 3.4.1, Slick 1.6.0, and Magnific Popup. Here Modernizr sits next to a current Bootstrap, which shows a theme that was updated one piece at a time instead of rebuilt.
The combinations are worth filtering on. Modernizr with jQuery 1.x is the strongest "not touched in a decade" signal. Modernizr with Google Hosted Libraries or the jQuery CDN means dependencies still come from public CDNs. Modernizr with jQuery carousel plugins or imagesLoaded points to an off-the-shelf theme. For the neighbouring libraries, see How to Detect jQuery and How to Detect Bootstrap.
FAQ
How do I check if a website uses Modernizr?
In DevTools, run typeof window.Modernizr. It returns "object" when the library is loaded, and Modernizr._version usually gives the version. Without a browser, grep the HTML for a script path containing modernizr. Through the API, call /demo or /analyze and look for name == "Modernizr" in technologies[].
How do I find a list of companies using Modernizr?
Use /lookup?tech=Modernizr to get domains already in the index, then check your own prospect list 10 URLs at a time with POST /analyze/batch.
Why is the Modernizr version empty?
The version is read from the script URL only, and most paths do not carry one in a form the rule can parse. Fetch the script and read the banner comment for the real version.
Can the API detect a bundled Modernizr build?
No. Without a script path containing modernizr, there is nothing for an HTTP scan to match. The DevTools console check will still find it.
Conclusion: Get a Free API Key and Start Scanning
Modernizr is a good legacy-stack signal because almost no one adds it to a new build. DetectZeStack detects it from the script tag path, which covers the self-hosted, CDN, and custom-build filenames most legacy sites use. It will miss bundled builds, and the version field is usually empty (and sometimes wrong), so check the banner comment when the exact version matters.
To build your list: one /demo call to check the response shape, /lookup for domains already in the index, /analyze/batch for your own list, and the script above to export it to your CRM. Each scan also returns the jQuery version, CMS, CDN, and hosting, so you get the whole stack from the same request.
Related Reading
- How to Detect jQuery on Any Website — the library that shows up next to Modernizr most often, with version parsing
- Find Companies Using jQuery CDN (code.jquery.com) — the delivery-host signal for jQuery-era front ends
- Find Companies Using imagesLoaded — another jQuery-era library used as a prospecting signal
- How to Detect if a Website Uses Bootstrap — CSS framework detection and version parsing
- Detect the JavaScript Framework a Website Uses — React, Vue, Angular, and what bundling does to detection
- Batch Scan 1,000 Websites for Tech Stack — concurrency, retries, and quota planning for large lists
- Build a Lead Enrichment Pipeline with Tech Detection — turning scan results into CRM-ready leads
Find Every Site Still Running Modernizr
One HTTP request returns every framework, library, CDN, CMS, and analytics tag on a page, with versions where the URL shows them. 100 requests per month free. No credit card.
Get your free API key