How to Detect parallax.js on Any Website (Free API)

September 21, 2026 · 9 min read

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 typeWhat it looks forUsable from an HTTP fetch?
jswindow.parallax, window.parallaxInstanceNo — requires a JavaScript runtime
scriptSrca <script src> whose filename matches parallax*.jsYes

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 pathMatches?What it actually is
/js/parallax.min.jsyesPixelCog parallax.js (true positive)
/js/jquery.parallax.jsyesOften a different jQuery parallax plugin
/js/simpleParallax.min.jsyessimpleParallax.js — unrelated, no jQuery
/js/universal-parallax.min.jsyesuniversal-parallax — unrelated
/js/parallax.pkgd.min.jsyesA 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:

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.

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:

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

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

Get API updates and tech detection tips

Join the mailing list. No spam, unsubscribe anytime.