Tech Stack Audit — Website Technology Detector with Evidence
Pricing
from $35.00 / 1,000 site audits
Tech Stack Audit — Website Technology Detector with Evidence
Detect a website's tech stack with a real browser: CMS, ecommerce, frameworks, CDN, analytics and pixels. Returns the version and how old it is, which trackers really fire, security headers, cookies set before consent — and the evidence for every detection.
Pricing
from $35.00 / 1,000 site audits
Rating
0.0
(0)
Developer
Power On Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Tech Stack Audit — website technology detector that shows its work
Point it at a website and get back its technology stack: CMS, ecommerce platform, JavaScript framework, web server, CDN, analytics, advertising pixels, consent platform, payment provider, and about 280 technologies in all.
Then it answers the three questions a plain technology list leaves open:
- Which version, and how old is it? Not "WordPress", but WordPress 6.4.3, on a line that shipped 2.8 years ago, 6.8 is newer.
- What actually runs? Not "the Meta Pixel tag is in the HTML", but the Meta Pixel really fired a network request on page load — or didn't.
- Is the site's own house in order? Security headers present, missing or weak, and which tracking cookies were written before anyone consented.
And for every single detection, the evidence: the exact header, script URL, cookie, meta tag, JavaScript global or DOM node that identified it.
A BuiltWith and Wappalyzer alternative that runs a real browser instead of reading the HTML and guessing.
Why the evidence matters
Every competing tool returns a list of names. A name you cannot check is a name you have to trust, and technology detection is guesswork often enough that trust is the wrong setting. So every technology in the output carries what proved it:
{"name": "jQuery","version": "3.6.0","confidence": 100,"activeAtRuntime": true,"evidence": [{ "type": "javascript global", "source": "window.jQuery — jQuery.fn.jquery = 3.6.0", "matched": "window.jQuery" },{ "type": "resource", "source": "https://www.php.net/js/vendor/jquery-3.6.0.min.js", "matched": "jquery-3.6.0", "seenIn": "markup and network" }],"versionAge": {"releasedOn": "2021-03-02","ageDays": 2014,"latestKnown": "3.7","outdated": true,"verdict": "jQuery 3.6.0 is on the current major line but line 3.6 shipped 5.5 years ago; 3.7 is newer."}}
You can verify that line yourself in ten seconds. That is the whole idea.
What a real browser buys you
Most technology lookups fetch the HTML and read the headers. That is fast and cheap, and it cannot see:
| Question | HTML-only scanner | This Actor |
|---|---|---|
| Is the Meta Pixel on this page? | It's in the markup | It's in the markup and it fired — or it's in the markup and never fired |
| Which third parties get visitor data? | The ones written into the page | Every domain the browser really contacted — 22 on a typical news site |
| Which cookies are set before consent? | Cannot know: no cookies are set without executing the page | The full list, classified, with lifetimes |
| Which tags a consent banner is actually blocking | Invisible | Reported as declared but not requested |
The audit clicks nothing — no banner is accepted, no button is pressed. That constraint is what lets the privacy section say "before consent" and mean it.
Sample output, one row per site
{"url": "https://example.com","reachedRealPage": true,"statusCode": 200,"technologyCount": 11,"technologyNames": ["WordPress", "jQuery", "Google Tag Manager", "Meta Pixel", "..."],"categories": { "CMS": ["WordPress"], "Advertising": ["Meta Pixel"], "...": [] },"cms": { "name": "WordPress", "version": "6.4.3", "outdated": true, "verdict": "…2.8 years ago…" },"jsFramework": { "name": "React", "version": null, "outdated": null, "verdict": null },"webServer": { "name": "nginx", "version": "1.18.0", "outdated": true, "verdict": "…" },"outdatedTechnologies": [ { "name": "PHP", "version": "7.4.33", "endOfLife": true, "verdict": "…no longer receives security fixes…" } ],"outdatedCount": 2,"endOfLifeCount": 1,"runtime": {"requestCount": 148,"thirdPartyDomainCount": 22,"technologiesActiveAtRuntime": ["Google Tag Manager", "Meta Pixel"],"technologiesDeclaredButNotRequested": ["Comscore"],"trackersFiring": ["Google Tag Manager", "Meta Pixel"]},"security": {"grade": "D", "score": 47, "https": true,"headersMissing": [ { "label": "HSTS", "cost": 18, "why": "Without HSTS a first visit over http can be intercepted…" } ],"headersWeak": [ { "label": "Content-Security-Policy", "warning": "Policy present but weak: allows 'unsafe-inline', allows any host (*) for scripts." } ],"softwareDisclosure": [ { "header": "x-powered-by", "value": "PHP/7.4.33", "versionLeak": true } ],"scoring": "Starts at 100. Each missing header costs its listed weight…"},"privacy": {"consentPlatformDetected": true,"consentPlatforms": ["OneTrust"],"trackersActiveBeforeConsent": ["Google Tag Manager"],"trackingCookiesBeforeConsent": [ { "name": "_fbp", "tracker": "Meta Pixel", "expiresInDays": 89 } ],"finding": "Consent platform present (OneTrust), but 1 tracker(s) and 1 tracking cookie(s) were already active before any choice was made."},"technologies": [ /* every detection, with its evidence */ ],"thirdPartyDomains": ["connect.facebook.net", "…"]}
What it's for
- Lead qualification — find every prospect running Shopify, or WooCommerce, or an end-of-life PHP.
- Competitive research — what a competitor's stack is, and how current.
- Agency pitches — walk in with "your WordPress is two years old, your PHP is end-of-life, and you have no CSP", each line backed by the header that proves it.
- Privacy and GDPR review — which trackers fire before consent, on your sites or a supplier's.
- Security triage at scale — a grade and a missing-header list per domain.
Input
Paste a list of websites. Bare domains are fine — example.com becomes
https://example.com.
| Field | Default | What it does |
|---|---|---|
urls | ["https://example.com"] | Websites to audit, one row of output per site |
device | desktop | desktop or mobile — some sites serve a different stack to phones |
minConfidence | 50 | Raise to 80 for detections proven by a decisive signal only |
includeEvidence | true | Attach the proof to every detection |
includeCookies | true | Full cookie list, with lifetimes and tracker attribution |
includeThirdPartyDomains | true | Every external domain really contacted |
includeRequestLog | false | Every network request, for auditing the evidence yourself |
waitUntil | load | load, domcontentloaded or networkidle |
settleMs | 1500 | Extra wait so late-firing tags are still caught |
timeoutSecs | 45 | Per site |
concurrency | 4 | Sites audited in parallel |
retries | 1 | Retries before a site is recorded as failed |
locale / timezone | en-US / — | Changes which consent banner and regional tags load |
Pricing
$0.05 per site audited — half what the two leading tech-stack Actors charge for a lookup that never opens a browser. No start fee, no subscription, no API key. Higher Apify plans pay less, down to $0.035.
You are not charged for:
- sites that failed to load — DNS failure, timeout, connection refused, TLS error;
- anything that answered 4xx or 5xx instead of a page;
- sites behind a bot wall, where the real page was never reached (see below).
Every row says which it was, in a charged field.
Read before you buy — two honest limits
1. Bot walls are reported, not defeated. Some sites answer a bot-detection challenge instead of their page: Cloudflare, Fastly, DataDome, Imperva, Akamai, AWS WAF, PerimeterX. This Actor recognises the wall, sets
reachedRealPage: false{ "reachedRealPage": false,"blockedBy": { "vendor": "Fastly", "marker": "Fastly client challenge","explanation": "…the technologies below describe the wall, not the site…" },"charged": false }
Getting past those walls reliably needs paid residential proxies. This Actor does
not use them. A scanner that meets a challenge page and cheerfully reports
"Cloudflare, nginx" has audited the wall, not the site, and given you no way to
tell — which is worse than saying so. If you have your own proxies, pass them in
the proxyConfiguration field.
2. The version table has a compile date, and it ships with every result.
Version age is judged against a bundled table of release lines and dates; the
date it was compiled is in every row as versionTableCompiledOn. If a site runs
something newer than the table knows, it is reported as newer than the table,
never as outdated. Where a version cannot be established the output says
ageDays: null and basis: "unknown" rather than inventing a verdict.
Coverage
About 280 technologies across 42 categories: CMS, ecommerce, headless CMS, website builders, page builders, JavaScript frameworks and libraries, UI frameworks, static site generators, build tools, analytics, session recording, tag managers, A/B testing, advertising and pixels, marketing automation, email marketing, customer support and chat, consent management, CDN, hosting, reverse proxies, web servers, programming languages, web frameworks, databases, security and bot management, search, payments, reviews, video, media, maps, fonts, authentication, backends, forms, scheduling, comments, monitoring and SEO.
Detection rules are written and maintained for this Actor. Version age is tracked for the technologies that realistically expose a version: WordPress, Drupal, Joomla, TYPO3, PHP, jQuery, Bootstrap, nginx, Apache, IIS, React, Next.js, Vue, Angular, AngularJS, Magento, PrestaShop, Shopware, Django, Laravel, Symfony, Rails, Ember, Font Awesome, Moment.js, Lodash, D3, GSAP, Video.js, Swiper, Alpine.js and htmx.
Use it from code
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });const run = await client.actor('power_on/tech-stack-audit').call({urls: ['https://example.com', 'https://another-site.com'],});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const site of items) {if (!site.ok || !site.reachedRealPage) continue;console.log(site.url, site.technologyNames.join(', '));for (const old of site.outdatedTechnologies) console.log(' ⚠', old.verdict);}
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("power_on/tech-stack-audit").call(run_input={"urls": ["https://example.com", "https://another-site.com"],})for site in client.dataset(run["defaultDatasetId"]).iterate_items():if not site.get("ok") or not site.get("reachedRealPage"):continueprint(site["url"], site["technologyNames"])for old in site["outdatedTechnologies"]:print(" !", old["verdict"])
Also from Power On Labs
- Website Screenshot & PDF Generator — full-page, viewport or element captures and page-to-PDF, with cookie banners removed.
- PDF to JSON Extractor — tables as real rows and columns, true reading order, key fields.