Website Tech Stack Detector: frameworks, CMS, analytics avatar

Website Tech Stack Detector: frameworks, CMS, analytics

Pricing

from $0.005 / actor start

Go to Apify Store
Website Tech Stack Detector: frameworks, CMS, analytics

Website Tech Stack Detector: frameworks, CMS, analytics

Detect the technology stack behind any list of websites: CMS, ecommerce platform, JavaScript framework, analytics, CDN, web server and more, with versions, confidence and the evidence for every match.

Pricing

from $0.005 / actor start

Rating

0.0

(0)

Developer

Michal Pšenčík

Michal Pšenčík

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Categories

Share

Website Tech Stack Detector (frameworks, CMS, analytics)

What does Website Tech Stack Detector do?

Give this Actor a list of websites and it tells you what each one is built with: the CMS, the ecommerce platform, the JavaScript framework, the analytics and tag managers, the CDN, the web server, the programming language and around a hundred other categories. Every match comes back with its category, its version where the site gives one away, a confidence score and the evidence — the exact header, cookie, script URL, meta tag or HTML pattern that produced it, so you can check a result instead of trusting it.

It fetches each site over plain HTTP, downloads its script files and searches those too. There is no browser, so a thousand domains cost you a few minutes rather than an hour.

Try it from the Input tab: leave everything at its default and hit Start to profile three well-known sites.

Why use Website Tech Stack Detector?

  • Sales prospecting. Filter a list of domains down to the ones running Shopify, HubSpot, WordPress or a competitor's product, then hand your team the ones worth calling.
  • Competitive and market research. Take any list of companies and count what they actually run, rather than what a vendor's case-study page claims.
  • Lead enrichment inside your own funnel. Feed the domains from your signup form through the Actor and attach the stack to each record in your CRM.
  • Security and compliance sweeps. Spot the sites in your estate still advertising an old server, an outdated jQuery, or a tag manager nobody remembers adding.
  • Agency audits. Produce the technology inventory slide for a pitch from a URL list in one run.

Every technology carries the evidence that produced it, which is the part most detectors leave out. When a result looks wrong you can see whether it came from a real fingerprint or from a Content-Security-Policy header that merely mentions a vendor.

How to use Website Tech Stack Detector

  1. Click Try for free (or open the Actor in Apify Console).
  2. On the Input tab, put your websites in Websites to analyse. You can paste them one per line, upload a CSV or text file, or link a Google Sheet. A bare domain like example.com works; it is read as https://example.com.
  3. Leave the rest alone for a first run. If you want fewer weak matches, raise Minimum confidence. If a site hides its stack deep in its JavaScript bundles, raise Scripts to download per site.
  4. Click Start. Ten sites take about ten seconds.
  5. Open the Output tab (or Storage → Dataset) and export as JSON, CSV, Excel or HTML, or pull it through the Apify API.

For a recurring inventory, use Schedules in Apify Console to re-run the same list every week and diff the results.

Input

All fields are optional; the defaults profile three sample sites.

FieldTypeDefaultDescription
startUrlsarraythree sample sitesThe websites to analyse. One dataset item comes back per URL. Accepts { "url": "..." } objects, a pasted list, an uploaded file or a Google Sheet.
maxItemsinteger1000Stop after this many URLs. 0 means no limit.
maxScriptsinteger8How many external JavaScript files to download and search per site. Inline scripts are always searched. 0 skips external scripts and makes runs faster.
minConfidenceinteger0Drop technologies detected below this confidence, 0 to 100.
includeFailedUrlsbooleantrueWrite a row for a URL that could not be fetched, with the error in it. A failed row is a dataset item and is billed as one. Set to false to skip them.
proxyConfigurationobjectApify proxy disabledOptional. The Actor fetches the URLs you supply, so no proxy is needed for most lists.

Example input:

{
"startUrls": [{ "url": "https://wordpress.org" }, { "url": "https://www.shopify.com" }],
"maxScripts": 8,
"minConfidence": 0
}

Output

Each website is one dataset item. Download the dataset in various formats such as JSON, HTML, CSV, or Excel.

The example below is a real run against https://wordpress.org, trimmed to five of the thirteen technologies it found and to the first two pieces of evidence each.

{
"url": "https://wordpress.org/",
"finalUrl": "https://wordpress.org/",
"statusCode": 200,
"success": true,
"error": null,
"technologies": [
{
"name": "WordPress",
"categories": ["CMS", "Blogs"],
"website": "https://wordpress.org",
"version": "7.2",
"confidence": 100,
"evidence": [
{
"type": "header",
"key": "link",
"pattern": "rel=\"https://api\\.w\\.org/\"",
"value": "rel=\"https://api.w.org/\""
},
{
"type": "meta",
"key": "generator",
"pattern": "^WordPress(?: ([\\d.]+))?",
"value": "WordPress 7.2"
}
]
},
{
"name": "Gutenberg",
"categories": ["WordPress plugins", "Editors"],
"website": "https://github.com/WordPress/gutenberg",
"version": "23.9.0",
"confidence": 100,
"evidence": [
{
"type": "scriptSrc",
"pattern": "/wp-content/plugins/gutenberg/",
"value": "/wp-content/plugins/gutenberg/",
"source": "https://wordpress.org/wp-content/plugins/gutenberg/build/modules/block-library/navigation/view.min.js?ver=1bf28ded04f9f188bdcb-20240308"
},
{
"type": "dom",
"key": "link[href*='/wp-content/plugins/gutenberg/'][href]",
"pattern": "/wp-content/plugins/gutenberg/.+\\.css(?:\\?ver=(\\d+(?:\\.\\d+)+))?",
"value": "/wp-content/plugins/gutenberg/build/styles/block-library/navigation/style.min.css?ver=23.9.0"
}
]
},
{
"name": "Nginx",
"categories": ["Web servers", "Reverse proxies"],
"website": "https://nginx.org/en",
"version": null,
"confidence": 100,
"evidence": [
{
"type": "header",
"key": "server",
"pattern": "nginx(?:/([\\d.]+))?",
"value": "nginx"
}
]
},
{
"name": "Google Tag Manager",
"categories": ["Tag managers"],
"website": "https://www.google.com/tagmanager",
"version": null,
"confidence": 100,
"evidence": [
{
"type": "html",
"pattern": "googletagmanager\\.com/ns\\.html[^>]+></iframe>",
"value": "googletagmanager.com/ns.html?id=GTM-P24PF4B\" height=\"0\" width=\"0\" style=\"display:none;visibility:hidden\"></iframe>"
}
]
},
{
"name": "MySQL",
"categories": ["Databases"],
"website": "https://mysql.com",
"version": null,
"confidence": 100,
"evidence": [
{
"type": "implied",
"pattern": "WordPress",
"value": "implied by WordPress"
}
]
}
],
"technologyNames": [
"Google Font API",
"Google Tag Manager",
"Gutenberg",
"HSTS",
"MySQL",
"Nginx",
"Open Graph",
"PHP",
"Priority Hints",
"RSS",
"WordPress",
"WordPress Block Editor",
"WordPress Site Editor"
],
"technologyCount": 13,
"categories": [
"Blogs",
"CMS",
"Databases",
"Editors",
"Font scripts",
"Miscellaneous",
"Page builders",
"Performance",
"Programming languages",
"Reverse proxies",
"Security",
"Tag managers",
"Web servers",
"WordPress plugins"
],
"scriptsFetched": 5,
"detectedAt": "2026-09-03T17:01:44.906Z"
}

A URL that could not be fetched comes back as a row too, so nothing disappears from your list silently:

{
"url": "https://this-domain-does-not-exist-98765.com/",
"finalUrl": null,
"statusCode": null,
"success": false,
"error": "getaddrinfo ENOTFOUND this-domain-does-not-exist-98765.com",
"technologies": [],
"technologyNames": [],
"technologyCount": 0,
"categories": [],
"scriptsFetched": 0,
"detectedAt": "2026-09-03T17:02:18.676Z"
}

Data fields

FieldDescription
urlThe URL as you supplied it.
finalUrlWhere it ended up after redirects.
statusCodeHTTP status of the final response. A 4xx or 5xx page is still analysed, because it still has headers.
successWhether the site could be fetched at all.
errorWhy it could not, when it could not.
technologiesEvery detected technology, most confident first.
technologyNamesThe same names as a flat list, so CSV and Excel exports stay readable.
categoriesEvery category present on the site, deduplicated.
scriptsFetchedHow many external script files were downloaded and searched.
detectedAtWhen the run started, in UTC.

Inside technologies, evidence[].type tells you where a match came from: header, cookie, meta, scriptSrc, script (inside a downloaded JavaScript file), html, text, css, url, dom, or implied when one technology necessarily brings another (WordPress implies PHP and MySQL).

How much does it cost to detect a website's tech stack?

This Actor uses pay per event pricing: $0.002 per website analysed, plus $0.005 per run start. Platform usage is included, so those two numbers are the whole bill.

Websites in the runCost
10$0.03
100$0.21
1,000$2.01
10,000$20.01

The most-used competing Actor on this Store charges $0.10 per detection, so the same 10,000 domains cost $1,000 there.

There are Actors on this Store charging a tenth of this, and they return a list of names: no version, no confidence, and no evidence you can check. This one also makes up to nine HTTP requests per site (the page plus its scripts) rather than one, which is what finds the bundler, the JavaScript library and the analytics tag that a single fetch of the HTML misses.

The Apify free plan comes with $5 of monthly platform credit, which covers around 2,000 websites.

To cap spending on a single run, set a maximum cost in the run options, or use the maxItems input.

Tips and advanced options

  • Analyse a deep page, not just the home page. A checkout URL reveals the payment processor, a blog post reveals the CMS plugins. The Actor fetches exactly the URL you give it and does not crawl.
  • Turn off external scripts for a fast, cheap pass. maxScripts: 0 cuts each site to one request. You keep every header, cookie, meta, HTML and inline-script fingerprint and lose only the ones that live inside bundled JavaScript files. Raise it to 30 when you care more about depth than speed.
  • Pay only for what was analysed. Set includeFailedUrls: false and dead domains cost nothing.
  • Cut the noise. minConfidence: 100 keeps only technologies backed by a strong or a repeated signal.
  • Exporting to a spreadsheet? Use technologyNames and categories. The full technologies array is nested and flattens badly into CSV.
  • Deduplicate on finalUrl. Two input URLs that redirect to the same site produce two rows.
  • Proxies are optional. You are fetching your own list of URLs, so there is no anti-bot surface. Turn on Apify Proxy datacenter groups only if a site refuses the platform's own IP range.

What it can and cannot see

The Actor reads what a site sends over HTTP: response headers, cookies, the HTML, the meta tags, the script URLs, and the contents of the JavaScript files it downloads. Roughly 86% of the fingerprint set can be evaluated that way.

The rest cannot, and the Actor does not pretend otherwise. Fingerprints that need a running JavaScript context (a global variable a framework sets at runtime), a DNS lookup, or a TLS certificate issuer are not evaluated. In practice this mostly costs you single-page applications that leave no trace in their server-rendered HTML.

FAQ, disclaimers and support

Does this Actor need an account or an API key anywhere? No. It fetches public pages with no login of any kind, and it uses no third-party detection API.

Is it legal to detect a website's technology stack? The Actor requests public pages the way a browser does and reads only what the server chooses to send. It does not log in, does not bypass any access control and does not collect personal data. You are responsible for the list of URLs you supply and for how you use the results.

Why did it miss React (or Vue, or Angular) on a site I know uses it? Those frameworks are often detected by a variable in the running page, which needs a browser. This Actor is HTTP-only by design, because that is what makes it fast and cheap. When a framework leaves a trace in the markup or the script URLs it is found; a fully client-rendered app with a generic bundle name may not be.

Why is a technology listed that the site does not obviously use? Check the evidence. Some fingerprints match a vendor named in a Content-Security-Policy header, which proves the site allows the vendor rather than that it currently loads it. Those rows say

"type": "header", "key": "content-security-policy"
, so they are easy to filter out. A handful of upstream fingerprints are also just loose; the evidence field is there so you can tell the difference.

What does confidence mean? It is the fingerprint author's weighting, not a probability. A single weak pattern scores 40 or 50, several independent patterns add up, and the total caps at 100.

Why is version usually null? Only some fingerprints capture a version, and only when the site exposes one, typically in a ?ver= query string, a meta generator tag or a server header. Most sites strip those.

Does it crawl the site? No. One request per URL you supply, plus its script files. If you want several pages of one site, put several URLs in the input.

Where do the fingerprints come from and how fresh are they? From a snapshot of the community Wappalyzer fingerprint set maintained at enthec/webappanalyzer, which is licensed GPL-3.0. Wappalyzer's own repository is gone and its npm package is unmaintained, so the community forks are where the data lives now. Around 7,600 technologies across 109 categories are covered. The snapshot is refreshed when the Actor is rebuilt.

Found a bug, or need something else? Open an issue on the Issues tab of this Actor and it will be picked up. If you need a fingerprint that is missing, or a browser-based version that can read JavaScript globals, mention it in the issue.