Website Tech Stack
Pricing
$3.00 / 1,000 analysed urls
Website Tech Stack
Detect the CMS, frameworks, analytics, CDN and server behind any URL list from HTML and response headers alone — no browser, no per-domain markup.
Pricing
$3.00 / 1,000 analysed urls
Rating
0.0
(0)
Developer
openrows
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Detect the CMS, JavaScript/web frameworks, analytics, CDN and web server behind any list of URLs — a fast, honest technology-stack detector for growth, sales-ops, SEO and competitive research.
Give it a list of URLs and it delivers a clean dataset (JSON, CSV, Excel, or through the API) of the technologies each page is built on. HTTP-only, no browser: one plain request per URL, so runs are fast and cheap.
Site-agnostic. You supply the URLs; this Actor only fetches what you point it at. See "Data and compliance" below.
What data you get
For every URL the Actor returns:
| Field | Description |
|---|---|
url | The URL that was analysed |
scrapedAt | ISO 8601 timestamp the result was written to the dataset |
fetchedAt | ISO 8601 timestamp the page was fetched |
server | Detected web server / reverse proxy, or the raw Server header if nothing matched |
cms | Detected CMS technologies (array) |
frameworks | Detected JS / web / UI frameworks (array) |
analytics | Detected analytics and tag-manager technologies (array) |
cdn | Detected CDN technologies (array) |
technologies | Every detected technology; shape depends on input (see below) |
httpHeaders | A small, fixed subset of the page's own response headers (see below) |
technologies[] is, by default, { name, category, version, confidence } per technology. With
compactOutput: true it drops to { name, category }. With categoriesOnly: true it drops
further, to a flat list of the distinct category names detected (no technology names, no
versions) — the smallest, cheapest shape.
httpHeaders is exactly these response header names, when present on the page: server,
x-powered-by, via, x-generator, x-drupal-cache, x-varnish, x-cache, cf-ray,
cf-cache-status, x-shopify-stage, x-aspnet-version, x-aspnetmvc-version,
x-turbo-charged-by, x-sourcemap — never the full header set, never Set-Cookie.
Input
| Option | Type | Default | Description |
|---|---|---|---|
urls | array of strings | — | Pages to analyse, one per line. One result per URL. Required. |
maxItems | integer | 100 | Stop after this many results (max 10,000). Also your cost cap. |
categoriesOnly | boolean | false | Return only the distinct technology categories per URL, nothing more. |
compactOutput | boolean | false | Drop httpHeaders and per-technology version/confidence detail. |
proxyConfiguration | object | Apify datacenter | Proxy settings |
urls takes plain URL strings, one per line in the Console editor (or a plain array of strings
through the API) — not the "Load URLs from a file" bulk-import mode some other Actors offer.
Example input:
{"urls": ["https://docs.apify.com/", "https://example.com/"],"maxItems": 50}
Output example
This is a real result from this Actor's own run against https://wordpress.org/ (not invented):
no Cloudflare and no jQuery front that page, and it carries Google Tag Manager, not Google
Analytics.
{"url": "https://wordpress.org/","scrapedAt": "2026-09-22T20:40:51.597Z","fetchedAt": "2026-09-22T20:40:51.597Z","server": "Nginx","cms": ["WordPress"],"frameworks": [],"analytics": [],"cdn": [],"technologies": [{ "name": "WordPress", "category": "CMS", "version": "7.2", "confidence": 100 },{ "name": "Google Tag Manager", "category": "Tag managers", "version": null, "confidence": 100 },{ "name": "Nginx", "category": "Web servers", "version": null, "confidence": 100 }],"httpHeaders": { "server": "nginx" }}
(Google Tag Manager's own category is "Tag managers", not "Analytics" — it does not appear in the
analytics summary field, only in technologies[].)
A run summary (items pushed, items skipped by category — including robotsDisallowed and
robotsUnknown — pages fetched, failed requests by category, stop reason, and a robots block
with the per-host outcomes — see "How robots.txt is handled" below) is stored in the run's
key-value store under the key OUTPUT.
Pricing
Pay per result. You are charged per result and nothing else: no platform usage, no compute units. Retries and failed requests are free. The current rate is on the Pricing tab of this Actor — that is the only place it is set, so no figure is repeated here.
maxItemscaps the number of results, and therefore the cost, of a run.- The run also stops when it reaches the maximum total charge you set for the run in Apify Console or through the API.
Tips
- Start with
maxItems: 20to check the fields before a large run. - Use
categoriesOnly: truewhen you only need to know whether a site runs a CMS, uses a CDN, etc. — not which one or which version. It is the cheapest way to read the output, though the price per result is the same; it only shrinks the payload. - A handful of well-known frameworks (Angular 2+, Svelte, Ember.js, Adobe Analytics, and a few others — see Limitations) are not detectable from HTML and headers alone and are not in this Actor's fingerprint set.
Limitations
- Detection is HTTP-only: one page load, no headless browser. Technologies whose only reliable signal is a DOM property, a JavaScript global, or a live probe request are not detected. The vendored fingerprint set (72 technologies — see below) was filtered down to exactly the technologies detectable this way; a small number of well-known frameworks that are only detectable via the DOM/JS (Angular 2+, Svelte, Ember.js, Material UI, Adobe Analytics, Cloudflare Turnstile, Remix, Bulma) are out of scope for this reason, not an oversight.
- Linked CSS/JS assets are matched by filename/path only (as referenced in the page's own HTML) — their contents are never fetched. A technology whose only signature lives inside a script's body (not its filename, the page's HTML, headers, meta tags or cookie names) will not be detected.
- Single-page apps that render most of their markup client-side may show fewer signals than a server-rendered page, because only the HTML delivered on the initial GET is inspected.
- Pages behind a login are not accessible and are not scraped.
Source caveats. The fingerprint database is a curated subset (72 of several thousand upstream entries) of a community-maintained, open technology-detection database — coverage is necessarily narrower than a full commercial tool's, and a technology's absence from the output does not always mean the site doesn't use it (see Limitations above). See "Third-party data" below for the source and its license.
Data and compliance
This Actor is site-agnostic: you choose the URLs, and you are responsible for the sites you point it at. Within that:
- It fetches only the URLs you give it — nothing is discovered, crawled or followed beyond them.
- It identifies itself honestly with an
openrows/website-tech-stackUser-Agent and sends no headers that imitate a browser (nosec-ch-*, nosec-fetch-*, no Chrome fingerprint). - It does not bypass access controls, solve CAPTCHAs, or retry past a block (401/403/429 is recorded and the request is abandoned, not retried under a different identity).
- It collects no personal data. The output is technology names, versions, categories and a
small fixed subset of response headers (server/cache/CDN signals only). Cookie names are
used as a detection signal (e.g.
_gaimplies Google Analytics); cookie values are never read or stored, and noSet-Cookievalue ever reaches the output.
How robots.txt is handled
Before the first page on a host is fetched, the Actor fetches that host's robots.txt once and
obeys it for the rest of the run. Rules are read for the product token openrows, falling back
to the * group when the file does not name us, with * and $ wildcards and the standard
"longest matching rule wins" precedence. A Crawl-delay set for us is honoured, up to 10 seconds.
When a page redirects, the URL the redirect actually leads to is checked again against its own
host's rules before anything is read from it, so a redirect cannot carry the Actor onto a site,
or a path, that its owner puts off limits.
- Disallowed URLs are never requested. They are reported under
skipped.robotsDisallowedin the run summary, so you can see exactly how many of your input URLs the site puts off limits. - No
robots.txt(404 or 410) means no rules, and the host is crawled normally. It is counted asrobotsAbsentin the summary. - A
robots.txtwe cannot read means the host is skipped, not crawled. Any other response — 401, 403, 429, a 5xx, a timeout, a network failure, or a 200 that turns out to be an error or login page — leaves us without the site's rules, and this Actor will not guess. Every URL on that host is skipped and counted underskipped.robotsUnknown, and the host and the status that stopped us are listed underrobots.unknownHostsin the summary. If a host you supplied returns no results, look there first.
Removal requests. If you believe this Actor's output is wrong or exposes something it should not, open an issue on the Actor's Issues tab and state the URL(s) concerned.
You are responsible for using this Actor, and the pages it fetches on your behalf, in line with the terms of each site you point it at and the laws that apply to you.
Third-party data: the fingerprint database
Technology detection is powered by a curated subset of the WebAppAnalyzer technology
fingerprint database (https://github.com/enthec/webappanalyzer), the community-maintained
continuation of the original Wappalyzer technologies.json (Wappalyzer's client went
closed-source in August 2023; the fingerprint data was continued as an open project). It is
used here under its GPL-3.0 license, vendored (never fetched from a third party at run
time) with full attribution and the license text included in this Actor's source. Full
provenance, license reasoning and the exact field subset kept: see THIRD_PARTY_NOTICES.md and
FINGERPRINTS_LICENSE.txt in this Actor's source.
Licence
This Actor's own source code is available under the GNU General Public License v3.0
(GPL-3.0) — see the LICENSE file in this Actor's source for the full text. It is licensed
this way because it vendors fingerprint data from the WebAppAnalyzer project
(https://github.com/enthec/webappanalyzer), which is itself GPL-3.0-licensed; see "Third-party
data" above and THIRD_PARTY_NOTICES.md for the full provenance and license reasoning.
Support
Report bugs and request fields on the Issues tab of this Actor. Include the run ID.