How to Detect parallax.js on Any Website (Free API)
parallax.js is the jQuery plugin from PixelCog that turns a background image into a scroll-reactive parallax layer with one attribute. It is old, it is small, and it is still bundled in a long tail of WordPress themes and agency-built marketing sites. Detecting it is easy in a browser and surprisingly subtle at scale, because the fingerprint that survives an HTTP fetch matches several unrelated libraries that happen to have "parallax" in the filename.
This post covers the manual checks for a single site, the one API call that answers the question at scale, and — the part most detection guides skip — exactly where that answer lies to you in both directions. Every response below came from a real call made while writing this, not from a hand-typed example.
What parallax.js Is and Why Its Footprint Is Easy to Miss
PixelCog's parallax.js attaches to an element, clones its background image into a fixed-position mirror layer, and repositions that layer on scroll. Usage is close to markup-only:
<div class="parallax-window" data-parallax="scroll" data-image-src="/img/hero.jpg"></div>
Because it is a jQuery plugin, a page running it necessarily runs jQuery too. Its own fingerprint in the open-source Wappalyzer taxonomy — the fingerprint set DetectZeStack's HTTP detection is built on — lists it under the exact name parallax.js, in the JavaScript libraries category, described as "Simple parallax scrolling effect" and pointing at github.com/pixelcog/parallax.js.
The One Signal That Survives Without Running JavaScript
That fingerprint declares two kinds of signal, and only one of them is reachable from a scan:
| Signal type | What it looks for | Usable from an HTTP fetch? |
|---|---|---|
| js | window.parallax, window.parallaxInstance | No — requires a JavaScript runtime |
| scriptSrc | a <script src> whose filename matches parallax*.js | Yes |
DetectZeStack fetches the HTML document over HTTP and parses it. It does not run a headless browser and does not execute page JavaScript. That means the js signals above can never fire for this technology: every parallax.js detection you get from the API comes from a script tag filename. Keep that in mind for the rest of this post — it explains both the false positives and the false negatives.
Manual Ways to Detect parallax.js in a Browser
For a single URL, the browser is still the fastest and most definitive tool, precisely because it does run the JavaScript.
DevTools Console Check
Open DevTools on the target page and paste this. It checks the plugin registration, the global, and the number of elements the plugin has actually claimed:
(function () {
var hasJQuery = typeof window.jQuery === 'function';
var hasPlugin = hasJQuery && typeof window.jQuery.fn.parallax === 'function';
var windows = document.querySelectorAll('[data-parallax], .parallax-window').length;
console.log({
jquery: hasJQuery,
parallaxPlugin: hasPlugin,
globalParallax: typeof window.parallax,
parallaxElements: windows
});
})();
On a page running PixelCog's plugin this prints something close to { jquery: true, parallaxPlugin: true, globalParallax: "undefined", parallaxElements: 3 }. The combination that matters is parallaxPlugin: true with a non-zero parallaxElements: that is the library loaded and in use. parallaxPlugin: true, parallaxElements: 0 means the file ships in the page but nothing on this route uses it — dead weight worth flagging in a performance review.
View-Source and curl grep for the Script Tag
The no-JavaScript version of the same question is a grep over the raw HTML. This is also the closest manual equivalent to what the API does:
curl -s https://pixelcog.github.io/parallax.js/ | grep -oE '[^"]*parallax[^"]*\.js' | sort -u
On the library's own demo page that prints, among other matches, ./js/parallax.min.js — the exact shape the detector is looking for. If the grep comes back empty on a site that visibly parallaxes as you scroll, the library is either bundled, renamed, or is not this library at all.
Detect parallax.js with One API Call
The console method is fine for one URL. It stops being practical the moment the question becomes "which of these 400 client sites still load a jQuery parallax plugin?" For that you want the same answer as structured JSON, one HTTP call per domain.
Free Public Demo Endpoint (No Key Required)
The public /demo endpoint runs the full detector pipeline against any URL with no authentication. It is IP rate-limited, but it is the fastest way to confirm the response shape before wiring up a key:
curl -s "https://detectzestack.com/demo?url=https://pixelcog.github.io/parallax.js/" | python3 -m json.tool
Run against the library's own demo page, that call returned the following (trimmed to the two entries that matter, with the full meta block intact):
{
"url": "https://pixelcog.github.io/parallax.js/",
"domain": "pixelcog.github.io",
"technologies": [
{
"name": "jQuery",
"version": "1.11.0",
"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"
},
{
"name": "parallax.js",
"categories": ["JavaScript libraries"],
"confidence": 100,
"description": "Simple parallax scrolling effect.",
"website": "https://github.com/pixelcog/parallax.js",
"source": "http"
}
],
"categories": {
"JavaScript libraries": ["jQuery", "parallax.js"]
},
"meta": { "status_code": 200, "tech_count": 8, "scan_depth": "full" },
"cached": false,
"response_ms": 166
}
Three things to read off that response. name is spelled parallax.js, lowercase, with the dot — use that exact string when you filter. version is absent, which is the common case and is explained below. And the co-detected jQuery 1.11.0 is not incidental: it is the dependency the plugin drags along, and on this page it is a 2014 release.
Authenticated /analyze Call and the Fields That Matter
For production use, call /analyze with a RapidAPI key. Same response shape as /demo, no demo rate limit, counted against your monthly quota:
curl -s "https://detectzestack.p.rapidapi.com/analyze?url=https://example.com" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com" \
| jq '.technologies[] | select(.name == "parallax.js")'
If the library is present, that prints the matching object; if not, jq prints nothing and exits cleanly — easy to drop into a shell loop over a domain list. When you only need a boolean and a version, /check answers in a flatter shape:
curl -s "https://detectzestack.p.rapidapi.com/check?tech=parallax.js&url=https://example.com" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com"
That returns domain, technology, detected, confidence, version, categories, response_ms, and cached — no technologies array to walk. There is also a /lookup?tech= endpoint that returns domains already in the index for a given technology name, which is the right call when you want a starting list rather than a per-domain verdict.
Scanning a List with POST /analyze/batch
The batch endpoint takes up to 10 URLs per request and fans them out server-side. Each URL counts against quota as one /analyze call would:
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://example.com", "https://example.org", "https://example.net"]}' \
| jq '.results[] | {url: .url, parallax: ([.result.technologies[]? | select(.name == "parallax.js")] | length > 0)}'
Note the shape difference: in a batch response each item nests the analysis under .result, alongside total_ms, successful, and failed counters at the top level. The filter above reduces it to one line per domain:
{ "url": "https://example.com", "parallax": false }
{ "url": "https://example.org", "parallax": false }
{ "url": "https://example.net", "parallax": false }
For lists longer than 10, loop in chunks — see Batch Scan 1,000 Websites for Tech Stack for concurrency, retry, and quota patterns.
How the Fingerprint Actually Works (and Where It Lies)
The scriptSrc pattern is deliberately loose: it allows optional path fragments (/jquery, /scripts, /assets/js, /wow), optional filename suffixes (.inview, .pkgd, .scrolling, .min, _move), and an optional leading version directory. It is also matched case-insensitively. That breadth is what makes it work across a decade of theme conventions — and what makes it ambiguous.
False Positives: Several Libraries Match the Same Rule
Testing the shipped pattern against real-world script paths, these all match and are all reported as parallax.js:
| Script path | Matches? | What it actually is |
|---|---|---|
| /js/parallax.min.js | yes | PixelCog parallax.js (true positive) |
| /js/jquery.parallax.js | yes | Often a different jQuery parallax plugin |
| /js/simpleParallax.min.js | yes | simpleParallax.js — unrelated, no jQuery |
| /js/universal-parallax.min.js | yes | universal-parallax — unrelated |
| /js/parallax.pkgd.min.js | yes | A packaged build, library unspecified |
This is not hypothetical. Matthew Wagerfield's parallax.js is a completely different library — it moves layers in response to gyroscope and mouse input, not scroll — and its demo page loads deploy/jquery.parallax.js. A live /demo call against it returns this, again trimmed to the JavaScript-library entries:
curl -s "https://detectzestack.com/demo?url=https://matthew.wagerfield.com/parallax/" | python3 -m json.tool
{
"url": "https://matthew.wagerfield.com/parallax/",
"domain": "matthew.wagerfield.com",
"technologies": [
{
"name": "jQuery",
"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"
},
{
"name": "parallax.js",
"categories": ["JavaScript libraries"],
"confidence": 100,
"description": "Simple parallax scrolling effect.",
"website": "https://github.com/pixelcog/parallax.js",
"source": "http"
}
],
"categories": {
"JavaScript libraries": ["jQuery", "parallax.js"]
},
"meta": { "status_code": 200, "tech_count": 6, "scan_depth": "full" },
"cached": false,
"response_ms": 271
}
Read the entry as a class, not a product. A parallax.js hit reliably means "this page loads a standalone parallax library from a script file named parallax-something." It does not, on its own, prove the library is PixelCog's. If the distinction matters for your use case, fetch the script file and read its header comment — every one of these libraries banners its own name and version in the first few lines.
False Negatives: Bundled, Renamed, or Hyphenated Files Are Invisible
The same pattern that is too generous on naming is strict about one thing: the word parallax must be followed directly by one of the known suffixes and then .js. Verified non-matches:
/assets/parallax-scroll.js— the hyphen breaks the pattern. No detection./js/parallaxie.js— extra letters after "parallax". No detection./js/rellax.min.jsand/js/jarallax.min.js— popular alternatives whose filenames do not contain "parallax" at all. No detection, correctly.- Any webpack or Vite bundle —
/assets/app.4f2c1a.jscontains the library but exposes no matching filename. No detection.
The bundling case is the one that bites audits. A modern build pipeline makes every bundled dependency invisible to filename-based detection, which is why an absent entry means "no matching script tag was served," not "the library is not there." For a portfolio audit, pair the API scan with the DevTools check on a sample of the misses.
Where the Version Number Comes From
Two places, both in the URL. A query string, as WordPress adds when a theme enqueues a script — /wp-content/themes/acme/js/parallax.js?ver=1.5.0 yields "version": "1.5.0". Or a versioned path segment ahead of the filename, as CDNs use — /1.5.0/parallax.js yields the same. A self-hosted /js/parallax.min.js with no version anywhere in the URL yields an empty version, which is what both live responses above show. Treat an empty string as "present, version not visible from this signal."
Technologies That Usually Appear Alongside parallax.js
Because /analyze returns the whole stack in one response, the neighbours come free — and they are often more useful than the parallax entry itself.
- jQuery — present in both live responses above, and effectively guaranteed for the jQuery-plugin variants. See How to Detect jQuery on Any Website for its own fingerprints and version parsing.
- Other jQuery UI plugins — a site with a parallax hero usually has a carousel too. Slick and OWL Carousel are the two most common companions, and a page carrying all three is a strong legacy-frontend signal.
- Bootstrap — the PixelCog demo page itself is built on it. See How to Detect if a Website Uses Bootstrap.
- WordPress — the
/wp-content/themes/path is where most self-hosted parallax files live, and it is also where the?ver=version string comes from. See How to Check if a Website Uses WordPress. - Library CDNs — when the file loads from a public CDN, that CDN is detected separately. See How to Detect cdnjs and Find Companies Using jsDelivr.
What to Do With a parallax.js Detection
On its own, "this site has a parallax plugin" is trivia. Paired with the rest of the response it becomes a usable signal in three situations:
- jQuery-removal audits. Parallax plugins are a classic blocker: nobody remembers the hero animation depends on jQuery until the dependency is pulled and the hero stops moving. Scanning a portfolio for
parallax.jsplusjQueryproduces the list of pages that need a replacement before the removal ticket can close. - Page-weight and Core Web Vitals reviews. A scroll-reactive background layer plus jQuery is two render-blocking dependencies serving one visual effect. A CSS-only or IntersectionObserver replacement is usually a same-day change, and the scan tells you which pages to start with.
- Agency and theme research. A self-hosted parallax file under
/wp-content/themes/alongside a carousel and Bootstrap is the fingerprint of an off-the-shelf or agency-built theme rather than a bespoke frontend. That is a fast read on how a competitor's site was assembled — and, if you sell modern frontend work, a qualified prospect list.
FAQ
How do I check if a website uses parallax.js?
In DevTools, run typeof jQuery.fn.parallax; it evaluates to "function" when the jQuery plugin is loaded. Without running JavaScript, grep the HTML for a script tag whose filename contains "parallax" and ends in .js. The API answer is a single /demo or /analyze call, filtering technologies[] for name == "parallax.js".
Why does the API report parallax.js on a site using a different parallax library?
The HTTP-layer fingerprint matches on the script filename, and jquery.parallax.js, simpleParallax.min.js, and universal-parallax.min.js all satisfy it. Read the entry as "a parallax library named parallax-something," and confirm the specific product by fetching the script and reading its header comment.
Can DetectZeStack detect parallax.js if it is bundled by webpack?
No. The scan fetches HTML and does not execute JavaScript, so a bundled or renamed file exposes no matching script tag. An absent entry means no matching script tag was served, not that the library is absent.
Why is the version field empty?
Version is parsed from the URL only — a ?ver= or ?v= query string, or a versioned path segment such as /1.5.0/parallax.js. Unversioned self-hosted paths yield an empty version while name still reports parallax.js.
Conclusion and Next Steps
Detecting parallax.js on one page is a one-liner in the console. Detecting it across a portfolio is one /analyze call per domain, or ten at a time through /analyze/batch. The detail that separates a useful audit from a misleading one is knowing what the entry actually asserts: a script tag whose filename matches a deliberately broad parallax pattern, matched case-insensitively, with no JavaScript executed. That makes it generous across several unrelated libraries and blind to anything bundled.
Used with that caveat in mind, it is a sharp signal — especially next to the jQuery entry that almost always sits beside it in the same response. And the same call that surfaces it names every other framework, library, CDN, CMS, and analytics tag on the page. One quota, one response shape, the whole stack.
Related Reading
- How to Detect jQuery on Any Website — the dependency every jQuery parallax plugin drags along, with real version parsing
- How to Detect Slick on Any Website — the carousel that shares the same legacy-theme stacks as parallax.js
- Find Companies Using OWL Carousel — the other big jQuery slider; run both filters to map the whole legacy frontend market
- How to Check if a Website Uses WordPress — where self-hosted parallax files live and where the ?ver= version string comes from
- How to Detect cdnjs on Any Website — the CDN path shape that supplies a version number when the filename does not
- Find Companies Using jsDelivr — the other major library CDN, and how its delivery signal is matched
- Detect the JavaScript Framework a Website Uses — what bundling does to library detection, one level up the stack
- Batch Scan 1,000 Websites for Tech Stack — concurrency, retries, and quota patterns for portfolio-scale scans
Detect parallax.js and Every Other Library in One API Call
One HTTP request returns every framework, library, CDN, CMS, and analytics tag on a page — with version strings where available. 100 requests per month free. No credit card.
Get your free API key