2026-08-14 · 8 min read
CMS Detection: How to Identify WordPress, Shopify, Wix, Webflow and Headless Sites
CMS detection is pattern matching on a public response, not a lookup in a registry. This guide walks through the six signal families every detector uses, the specific fingerprints for WordPress, Shopify, Wix and Webflow, and the two situations — headless architectures and stripped headers — where detection quietly stops working.
"What CMS is this site running?" sounds like a database question. It is not. There is no registry to look up. Every answer is pattern matching against whatever the site happens to expose in its public response — a meta tag, an asset URL, a cookie name, a header. That works remarkably well most of the time, and fails in specific, predictable ways the rest. Knowing which is which is the difference between a useful audit and a confident wrong answer.
Scale first, for context. The HTTP Archive Web Almanac 2025 found CMS-driven sites account for over 54% of observed websites, with WordPress at roughly 64% of CMS sites — about 35.6% of the web overall. Shopify sits around 7.3–7.8% of CMS share, Wix around 5%, Squarespace around 3%.
What CMS detection actually measures
A detector fetches a page and looks for evidence that a particular platform generated it. Nothing more. It cannot see the admin panel, the database or the deployment pipeline. It sees the HTML, the response headers, the URLs of the assets that page references, and any cookies set on the response.
That matters because the honest output is not "this site runs WordPress". It is "this response contains markers consistent with WordPress". Usually the same thing. Sometimes not — and that gap is where a checker earns or loses credibility.
Six signal families
Practically every detector on the market, ours included, draws from the same six categories.
Meta generator tags. The most direct signal and the least reliable. <meta name="generator" content="WordPress 6.9"> is a self-declaration emitted by default. It is also one line of code away from being removed, and most hardened WordPress installs strip it.
Asset paths. URLs that reveal directory conventions: /wp-content/ and /wp-includes/ for WordPress, cdn.shopify.com for Shopify, static.parastorage.com for Wix. Harder to remove than a meta tag, because the site would stop working.
Cookies. Platform-set cookies with recognisable names — with an important caveat: many of the best-known ones only appear for authenticated users. WordPress's wordpress_logged_in_* and wp-settings-* cookies are absent on an anonymous request, so a detector never sees them.
HTTP response headers. Vendor headers are strong evidence when present, because infrastructure sets them rather than the page. Reading HTTP headers properly is its own topic; the short version is that vendor-prefixed headers tell you more than the standard ones.
Script URLs and inline objects. JavaScript globals and bundle paths: __NEXT_DATA__ for Next.js, Shopify.theme for Shopify, /_next/static/ chunks.
API and discovery endpoints. WordPress advertises its REST API in both a header and a link tag. Per the WordPress REST API handbook, the header is Link: <https://example.com/wp-json/>; rel="https://api.w.org/". That relation value is specific enough to be near-conclusive.
Single signals are hints. Two or three independent signals agreeing is a detection.
WordPress: easiest to spot, easiest to get wrong
WordPress leaves more traces than anything else, largely because its asset layout is baked into how themes and plugins are written:
/wp-content/and/wp-includes/in asset URLs<meta name="generator" content="WordPress x.y">- the REST discovery header with
rel="https://api.w.org/", or?rest_route=/on sites without pretty permalinks - plugin and theme paths under
/wp-content/plugins/and/wp-content/themes/, which often expose version strings in query parameters
The complication is headless WordPress: WordPress runs the editorial back end while a separate front end, often Next.js, renders the public site. There is then no /wp-content/ and no generator tag. WordPress genuinely powers the site and no external detector will say so.
The mirror-image error exists too. A site migrated off WordPress can keep serving old images from a /wp-content/ path for years, and one leftover URL is enough to make a naive detector report a CMS that was decommissioned in 2021.
Shopify, Wix and Webflow: managed platforms fingerprint hard
Hosted platforms are easier, because you cannot reconfigure infrastructure you do not control.
Shopify is confirmed by response headers its routing layer injects: x-shopid, x-shopify-stage, and x-sorting-hat-shopid / x-sorting-hat-podid. Front-end signals back them up — assets from cdn.shopify.com, the Shopify.theme JavaScript object, and _shopify_y / _shopify_s analytics cookies. Custom storefronts on Shopify's Hydrogen framework are a different matter: the checkout stays on Shopify infrastructure, but the storefront itself may show none of the classic theme markers.
Wix emits <meta name="generator" content="Wix.com Website Builder"/> and serves its static assets from static.parastorage.com and static.wixstatic.com. It also exposes a site identifier header, X-Wix-Meta-Site-Id, a permanent UUID that identifies the site independently of the domain pointed at it.
Webflow marks the <html> element with data-wf-site and data-wf-page attributes (and often data-wf-domain), ships a <meta name="generator" content="Webflow"> tag, and uses a distinctive CSS class prefix — w-nav, w-layout-grid, w-dyn-item. Assets come from cdn.prod.website-files.com, with older sites still referencing assets.website-files.com or uploads-ssl.webflow.com. Note that Webflow supports code export: an exported site keeps the w- classes and often the data attributes, while being hosted anywhere. The markup is Webflow; the hosting is not.
Headless and hybrid: where detection breaks
Headless is the honest hard case. When the content system and the rendering layer are separated, the public response describes the renderer, not the CMS.
What you can usually see is the front-end framework. Next.js exposes /_next/static/ asset paths and a __NEXT_DATA__ script block, sometimes x-powered-by: Next.js (disabled by many production sites via poweredByHeader: false) and x-nextjs-cache on statically generated pages. Nuxt exposes a __NUXT__ global. Astro emits a versioned generator meta tag. The hosting platform often signs its own headers too — x-vercel-id and x-vercel-cache on Vercel, x-nf-request-id on Netlify.
What you generally cannot see is which CMS fills that front end. Contentful, Sanity, Strapi, Directus or headless WordPress all produce plain rendered HTML with no residue. If a detector confidently names the CMS behind a headless front end, it is either reading a build artefact that happens to leak, or it is guessing.
The correct answer for these sites is a two-layer one: "Next.js front end on Vercel; content source not externally determinable." That is less satisfying than a logo, and considerably more accurate. It is the same problem origin hiding creates for hosting detection — a layer in front of the thing you want to identify.
Limitations and false positives
The specific ways CMS detection goes wrong, in rough order of how often we see them:
- Stripped fingerprints. Security plugins and hardening guides remove the generator tag and vendor headers. Absence of evidence is not evidence of absence — a hardened WordPress site can look hand-built.
- CDN and WAF interference. A proxy in front of the site can strip or rewrite response headers, so vendor headers vanish while the HTML stays intact. Working out which CDN is in the path tells you whether to trust the headers at all.
- Multiple platforms on one page. A Shopify Buy Button embedded on a WordPress site produces genuine signals for both. Neither is wrong; a detector that reports a single winner is.
- Stale assets and stale caches. Old paths outlive the platform that created them, and both our results and the CDN's are cached — a site that migrated last week can still report the old stack.
- Version numbers are self-reported. A generator tag claiming a version is a claim, not a measurement, and frequently a stale one.
- Homepage-only checks. A marketing homepage may run one platform while the blog or the shop runs another. One URL is one data point.
- Detection is not permission. A detected plugin or version string is public information about a public response. It is a reason to check whether something is out of date, not a vulnerability report.
What hostingchecker.org reports, and what to do with it
Our check pipeline runs a CMS probe alongside the DNS, WHOIS, HTTP, SSL, CDN and MX probes, plus a WordPress-specific plugin probe when WordPress markers appear. Results feed public taxonomy pages at /cms and /cms/{slug}, aggregated from real checks rather than a static database. Where signals conflict or are absent, the report says so instead of picking a winner.
Four things the answer is actually good for:
- Security. The platform tells you which advisories apply and which exposed version strings are worth chasing. Pair it with a security headers check.
- Performance. Platform choice constrains what you can fix. Page-builder markup and plugin bloat are a different problem from a slow origin.
- Migration planning. What a site runs, plus its CDN and host, is step one of scoping a move. Pair with hosting detection.
- Competitor research. Platform mix across a set of domains is a real signal about budget and team — as long as you treat the sample as "sites where detection worked", not "all sites".
Summary
CMS detection is inference from a public response, and its accuracy tracks how much a platform is willing to reveal. Managed platforms fingerprint clearly because their infrastructure signs the response. WordPress fingerprints clearly until someone hardens it or goes headless. Headless architectures, by design, tell you about the renderer and nothing about the content source.
Read a detection result as a claim with a confidence level attached, check whether two independent signals agree, and stay sceptical of any tool that confidently names a CMS behind a headless front end.
Check your site — run a domain through hostingchecker.org to see the CMS, hosting, CDN and header signals side by side, and which ones actually agreed.
