Website Technology Detector — Tech Stack Lookup
Pricing
from $0.60 / 1,000 site analyseds
Website Technology Detector — Tech Stack Lookup
Find out what any website runs on. One row per site: CMS, e-commerce platform, JavaScript framework, analytics, ad pixels, live chat, payments, CDN, hosting, web server and security, each with the evidence that proved it. 232 signatures, no API key, no browser.
Pricing
from $0.60 / 1,000 site analyseds
Rating
0.0
(0)
Developer
Insight Solutions
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
11 hours ago
Last modified
Categories
Share
Find out what any website runs on. Give this Actor a list of domains and get back one row per site: the CMS, the store platform, the JavaScript framework, every analytics tag and ad pixel, the chat widget, the payment providers, the CDN, the host, the web server and the bot-management vendor sitting in front of it — each detection carrying the evidence that proved it, so you can check any answer yourself.
No API key. No browser. No JavaScript execution. $1.00 per 1,000 sites, proxy included, dead domains are free, and a run that reads nothing costs nothing at all.
Try it in 30 seconds
{"websites": ["allbirds.com", "vercel.com", "techcrunch.com", "webflow.com", "hubspot.com"]}
A bare domain is enough. Each one is tried on https://, then https://www., then plain http://, so a host that only answers on one of them still gets read.
What comes back
{"ok": true,"rowType": "site", // "site" | "technology" | "diagnostic""input": "allbirds.com","domain": "allbirds.com","url": "https://www.allbirds.com/", // where the request actually landed"statusCode": 200,"title": "Allbirds: Comfortable, Sustainable Shoes & Apparel","description": "The world's most comfortable shoes, made with natural materials…","language": "en-us","generator": null, // the site's own <meta name="generator">"server": "cloudflare","partial": false, // true only when a bot wall answered instead"technologies": [{"name": "Shopify","category": "E-commerce","website": "https://www.shopify.com","version": "[DNAM Theme July 2026]", // Shopify publishes the theme, not a version"confidence": 100,"evidence": ["headers: header powered-by: Shopify","cookies: cookie _shopify_y=2a063abf-e67c-4dd1-9c31-79d91f9eb39c","meta: meta shopify-checkout-api-token: 1bd27af8770b91f6f7cab7cc85cba04d"]},{ "name": "Cloudflare", "category": "CDN", "confidence": 100, "evidence": ["headers: header cf-ray: a38f37e6bc395711-PHX"] },{ "name": "Shop Pay", "category": "Payments", "confidence": 95, "evidence": ["assets: asset: https://shop.app/checkouts/internal/preloads.js…"] },{ "name": "Google Tag Manager", "category": "Tag manager", "confidence": 95, "evidence": ["assets: asset: https://www.googletagmanager.com/ns.html?id=GTM-TH8KRSBJ"] }],"technologyNames": ["Cloudflare", "Shopify", "Shop Pay", "Google Tag Manager", "Alpine.js", "…"],"categories": {"E-commerce": ["Shopify"],"CDN": ["Cloudflare"],"Payments": ["Shop Pay"]},// the flat columns, for filtering and for spreadsheets"cms": null,"ecommercePlatform": "Shopify","jsFramework": "Alpine.js","analytics": ["Amplitude", "Google Tag Manager"],"advertising": [],"chat": [],"payments": ["Shop Pay"],"cdn": ["Cloudflare"],"hosting": null,"security": [],"hasCookieBanner": true,"scriptCount": 38,"externalDomains": ["cdn.shopify.com", "www.googletagmanager.com", "shop.app"],"pagesFetched": ["https://www.allbirds.com/"],"error": null,"errorType": null,"fetchedAt": "2026-09-10T14:45:46.000Z","scrapedAt": "2026-09-10T14:45:46.120Z","source": "website","sourceUrl": "https://www.allbirds.com/"}
With "rowPerTechnology": true, every detection also gets its own flat row carrying name, category, version, confidence and evidence — the shape you want for a pivot table or a warehouse load.
Use cases
- Lead qualification and prospecting — filter a list of domains down to the ones running Shopify, HubSpot, Klaviyo or whatever your product plugs into.
ecommercePlatform,cmsandtechnologyNamesare the columns to sort on. - Competitive and market research — count how many sites in a segment run WordPress versus Webflow, or which analytics stack a whole industry has settled on.
- Partner and integration targeting — find the sites already running the platform you build extensions for, and the ones running the competitor you displace.
- Agency audits and pitches — walk into a meeting knowing the prospect's CMS, page weight, ad pixels and consent platform before anyone opens a laptop.
- Security and vendor mapping — which of your suppliers sit behind Cloudflare, DataDome or Akamai, and which have no bot management at all.
- Compliance sweeps —
hasCookieBannerplus theCookie consentcategory against a portfolio of domains, in one run. - Monitoring a migration — re-run a list weekly and diff
technologyNamesto catch the day a customer moves off your platform.
How it works, and why it keeps working
A website tells you what it runs on in five places, and this Actor reads all five out of a single HTTP response:
| Where | What it gives away | Confidence |
|---|---|---|
| Response headers | Server: Squarespace, x-powered-by: Next.js, x-hs-hub-id, cf-ray, x-wix-request-id, x-vercel-id | 100 |
| Cookies the server set | _shopify_y, __cf_bm, datadome, PHPSESSID, laravel_session | 100 |
| Script and asset URLs | cdn.shopify.com, /_next/static/, js.stripe.com, widget.intercom.io, and every preconnect and preload alongside them | 95–100 |
| Meta tags | <meta name="generator" content="WordPress 6.9.7">, shopify-checkout-api-token, og:* | 90 |
| The markup and inline JS | data-wf-page, _nghost-, svelte-1fusfkr, wp-content/themes/…, window.intercomSettings | 60–80 |
Three decisions are worth knowing about, because they are what separates a useful answer from a noisy one:
Evidence is scored, and it is shown to you. Confidence is not a guess about how popular a product is. It is how good the evidence was: a header the server itself set outranks a string somewhere in the body, and both outrank a global name mentioned in inline JavaScript. Every detection carries up to four evidence lines naming exactly what matched, truncated to 120 characters — so a detection you doubt takes ten seconds to check rather than a support ticket.
First-party assets only, where it matters. A news site that embeds one image from a WordPress blog's CDN is not running WordPress. Platform signatures are restricted to assets on the site's own registrable domain, which is why nytimes.com does not come back as WordPress even though wp-content/ appears in its markup. Signatures where that restriction would be wrong — a Stripe script is a Stripe script wherever it is hosted — do not use it.
A blocked page is still an answer. When a site serves an anti-bot interstitial, that interstitial names the vendor the site pays for. Rather than throwing the response away, the row comes back with partial: true, the security vendor and the CDN filled in, and an error saying what refused. That is worth more than an empty diagnostic, and it is charged as one site. A challenge page that revealed nothing is a free diagnostic row.
The fingerprint database — 232 signatures across 26 categories — was written from scratch for this Actor and is in src/fingerprints.js, one readable object per product. It is not derived from any third-party fingerprint set.
How it compares
- The evidence ships with the answer. Most technology lookups hand you a label. This hands you the label and the header, cookie or URL it came from, so you can audit a list of 10,000 domains by spot-checking twenty.
- Bulk by design, priced by the domain. No monthly minimum, no per-seat licence, no rate card that changes at 10,000 lookups. One JSON array in, one flat table out.
- Live, not a database lookup. Every run reads the site at that moment. Nothing here is a cached crawl from six months ago, which is the failure mode of the databases these tools usually sit on.
- Failures are free and legible. A dead domain, a URL that answers with a PDF, or a site that ran out the clock produces a diagnostic row with an
errorTypeyou can branch on — and no charge. A run that reads nothing at all finishes FAILED with the reason in its status message, never a green run containing an apology. - No browser. Detection is pure HTTP and regular expressions, which is why a thousand domains cost dollars rather than hundreds of dollars — and why a site whose stack only appears after client-side rendering is a documented limitation rather than a hidden one.
Input reference
| Field | Type | Default | What it does |
|---|---|---|---|
websites (required) | array of strings | five example domains | Bare domains or full URLs. Each is tried https:// → https://www. → http://. A URL with a real path is fetched exactly as given. Duplicates are read, and billed, once |
extraPages | integer 0–3 | 0 | Internal pages to read in addition to the entry page, shallowest links first. Costs requests and time; never costs an extra site charge |
rowPerTechnology | boolean | false | Also write one flat row per detection, at $0.0001 each. The site rows are still written, first |
categories | array | [] (all) | Restrict the output to chosen categories. The flat columns follow the filter |
minConfidence | integer 0–100 | 50 | Drop detections scored below this. 100 = a header or cookie; 90 = a generator meta; 60 = an inline-JS global |
maxConcurrency | integer 1–20 | 5 | Sites in parallel. Each worker keeps its own proxy session |
maxRunSecs | integer 30–3600 | 240 | Whole-run wall-clock budget. When it runs out the Actor keeps what it has and files a free diagnostic row for each site it never reached |
proxyConfiguration | object | Apify datacenter | Switch the group to RESIDENTIAL for sites behind an aggressive bot wall. Datacenter is the default because it is cheaper and ordinary websites accept it |
Output reference
Every row carries the same keys. ok: true is a site or technology row; ok: false is a free diagnostic row.
| Field | What it is |
|---|---|
rowType | site, technology or diagnostic |
input, domain, url, statusCode | The entry you supplied, its registrable domain, the URL the request landed on, and the status |
title, description, language, generator, server | Page metadata, read straight off the entry page |
partial | True when a bot wall answered instead of the site. The row then holds the wall, not the stack |
technologies | Every detection: name, category, website, version, confidence, evidence[] |
technologyNames, categories | The same list flattened, and grouped by category |
cms, ecommercePlatform, jsFramework, hosting | The single best answer in each of those four categories |
analytics, advertising, chat, payments, cdn, security | Every detection in each of those categories |
hasCookieBanner | A named consent platform, or an unmistakable consent-banner marker |
scriptCount, externalDomains, pagesFetched | How heavy the front end is, the top 25 third-party hosts, and which pages went into this row |
name, category, version, confidence, evidence | Filled in on a technology row; null on a site row |
ok, error, errorType | Whether this row is a result, and if not, why not |
fetchedAt, scrapedAt, source, sourceUrl | When the page was read, when the row was written, and from where |
errorType on a diagnostic row is one of:
| Value | Meaning | Charged? |
|---|---|---|
unreachable | Nothing answered on any of the four addresses. A dead domain, a parked domain, or a host with no web server | No |
blocked | The site refused the request, or served an interstitial that revealed nothing identifiable | No |
not-html | The URL answered with a file rather than a page — a PDF, an image, a JSON feed | No |
http-error | An error status with no readable page behind it | No |
timeout | The run's maxRunSecs budget ran out before this site was reached | No |
invalid-input | The entry was not a fetchable domain — an email address, an IP, a bare word | No |
Pricing
$1.00 per 1,000 sites. Pay-per-event, with the proxy already inside that number — there is no separate proxy line on your bill for this Actor.
| Event | What triggers it | FREE | Starter | Scale | Business |
|---|---|---|---|---|---|
| Site analysed (primary) | One website written to your dataset | $0.001 | $0.001 | $0.0008 | $0.0006 |
| Technology row | One extra flat row, only when rowPerTechnology is on | $0.0001 | $0.0001 | $0.0001 | $0.0001 |
| Run started | Once per run, after the first site is analysed | $0.001 | $0.001 | $0.001 | $0.001 |
One site is one charge whether it returned three detections or thirty, and whether extraPages made the Actor read one page or four.
Worked example. 500 domains from a scraped lead list, of which 40 turn out to be dead:
- 460 sites × $0.001 = $0.46
- 1 run start = $0.001
- 40 dead domains = $0.00
- Total: $0.461
What you are never charged for: a domain that resolves nowhere, a URL that answers with a file, an entry that was not a website, a site the run never reached before maxRunSecs, or a challenge page that revealed nothing. If a whole run comes back empty it finishes FAILED and bills nothing at all, start fee included.
Set ACTOR_MAX_TOTAL_CHARGE_USD on a run and the Actor stops fetching once the ceiling is in sight, rather than handing you rows it cannot bill or billing you for rows it cannot hand over. It finishes SUCCEEDED with the ceiling named in its status message, and everything already delivered is yours.
Limits, and the ones that might bite
No browser, so nothing that only exists after rendering is seen. This Actor reads the HTML a server returns. A single-page app that injects its analytics tag from JavaScript at runtime, a chat widget loaded by a tag manager three hops deep, a payment button that only mounts on the checkout page — none of those are in the initial document, and none of them will be detected from a home page. extraPages helps with the second and third; nothing helps with the first, and a tool that claims otherwise is running a browser and charging accordingly.
Absence is not evidence of absence. A row that does not name Klaviyo means Klaviyo was not visible on the pages that were read. It does not mean the site is not a Klaviyo customer. Treat the detections as a floor, never as a complete inventory — this matters most when you are counting how many sites in a list lack something.
Detection is only as good as the fingerprint. 232 signatures is a lot of the web, not all of it. Products with no public marker — a self-hosted backend, a first-party analytics pipeline, a white-labelled widget served from the site's own domain — leave nothing to match on. Regional platforms outside the English-speaking web are thinner than the ones listed here.
Tailwind CSS is a heuristic, and it is labelled as one. Compiled Tailwind leaves no file to point at, so it is detected from the utility-class dialect itself and only when six of eight distinct class families are present. It scores 60, and its evidence line says exactly that. Raise minConfidence above 60 to exclude it.
Versions are reported only where a site publishes one. generator metas, versioned asset URLs and CDN paths give real numbers; most modern stacks give none. A null version means the page did not say, not that the version is unknown to anyone.
A www. and an apex host are two entries. Sending both reads and bills both. That is deliberate — a caller sending both is usually testing exactly that difference — but it is worth knowing before you paste a list with duplicates in two spellings.
Sites behind aggressive bot management may refuse the default proxy. The datacenter default is right for the overwhelming majority of the web and wrong for the small slice that fingerprints every request. Those sites come back as partial: true rows naming their security vendor; switch proxyConfiguration to RESIDENTIAL and re-run them if you need what is behind the wall.
The upstream format may change. Websites are rebuilt, vendors rename their CDN hosts, and a signature that worked last month can go quiet. When that happens a technology stops appearing — it does not turn into a wrong answer — and the evidence column is how you find out which one.
Use it from an AI agent, or from code
One JSON object in, one flat array out — the shape agent runtimes want. The Actor runs with limited permissions, uses pay-per-event pricing and never enters Standby, so it works over the Apify MCP server and with x402 agentic payments. The Integrations tab pushes results to Slack, a webhook, Zapier, Make, Google Sheets, Snowflake or BigQuery.
curl -X POST "https://api.apify.com/v2/acts/insight.solutions~website-tech-detector/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"websites":["allbirds.com","gymshark.com"],"minConfidence":90}'
# pip install apify-clientfrom apify_client import ApifyClientclient = ApifyClient("<APIFY_TOKEN>")run = client.actor("insight.solutions/website-tech-detector").call(run_input={"websites": ["allbirds.com", "vercel.com", "techcrunch.com"],"categories": ["E-commerce", "Marketing automation", "Analytics"],"minConfidence": 90,})for row in client.dataset(run["defaultDatasetId"]).iterate_items():if not row.get("ok"):print("skipped:", row["input"], row["errorType"])continueprint(row["domain"], "→", ", ".join(row["technologyNames"]) or "nothing detected")
Switch rowPerTechnology on when the destination is a table rather than a document — one row per detection loads into a warehouse without a JSON parser.
FAQ
How accurate is it? Accurate enough to act on, and honest about where it is not. Every detection carries the evidence that produced it and a confidence score derived from what kind of evidence that was. Every detection on all twenty real homepages in the test suite was read by hand during development and traced back to something the page genuinely publishes, and the suite then pins the traps down site by site: nytimes.com is not WordPress, github.com is not GitHub Pages, bigcommerce.com's marketing site is Next.js on Vercel and not a BigCommerce storefront, allbirds.com is not running hCaptcha because a script mentions the field name.
Why does a site I know runs X not show X?
Almost always because X is not in the initial HTML: it is injected by a tag manager, mounted by client-side JavaScript, or only present on a page this run did not read. Try extraPages: 2. If it still does not appear, the product left no public marker on that page, and no HTTP-only tool will find it.
What does confidence actually mean?
How strong the evidence was, not how likely the product is. 100 = a response header or a cookie the server set. 95–100 = a script or asset URL. 90 = a <meta name="generator">. 80 = a string in the page body. 75 = an attribute or class-name shape. 70 = added because another detection implies it. 60 = a global named in inline JavaScript.
What is implied by in the evidence?
Some technologies cannot run without others. Next.js implies React and Node.js; WooCommerce implies WordPress, which implies PHP and MySQL. Those are added at confidence 70 with an evidence line naming what implied them, so "we saw it" and "it cannot work without it" are never confused.
Does it respect robots.txt?
This Actor reads a site's home page the way a browser does — one request, no crawl. It does not walk a site, does not follow paginated listings, and by default does not go past the entry page at all. With extraPages on it reads at most three more linked pages, spaced 250–600 ms apart.
Can I check 50,000 domains?
Yes. Raise maxConcurrency and maxRunSecs, and bound the spend with ACTOR_MAX_TOTAL_CHARGE_USD. At $0.001 per site that is $50 for the list, and the run stops cleanly at whatever ceiling you set.
What happens if one domain fails?
The others still run. The failed one produces a free diagnostic row and the run finishes SUCCEEDED. If every domain fails, the run finishes FAILED and you are billed nothing at all.
Do I need my own proxy?
No. Apify's datacenter proxy is configured by default and its cost is inside the per-site price. Switch the group to RESIDENTIAL in the same field if a set of targets refuses datacenter addresses.
Is the data fresh? Live. Every run reads the site at that moment; nothing is cached, and there is no lookup database behind this.
Legal and data-protection notes
- Public pages only. Every source is a page a browser would load without signing in. The Actor never logs in, never accepts cookies or session tokens, never takes an API key belonging to anyone else, and never touches anything behind authentication.
- This is not personal data. A technology profile describes a website's infrastructure, not a person. Nothing in the output identifies an individual, and no contact details, names or user records are collected.
- The fingerprint database is our own work. Every signature in
src/fingerprints.jswas written from general knowledge of how these products identify themselves on the wire and verified against real captured homepages. Nothing in it is copied from, generated from, or derived from Wappalyzer, webappanalyzer or any other third-party fingerprint set. - Detections are observations, not endorsements or contracts. "Site X loads Stripe's script" is what was seen; it is not a claim about a commercial relationship, and it should not be presented as one.
- Not affiliated with any of the vendors named in the output. All product names and trademarks belong to their respective owners and are used only to describe which public artefacts this Actor recognises.
Our other Actors
Every Insight Solutions Actor is pay-per-result with no browser, no login and no API key, and every one of them returns free diagnostic rows instead of billing for failures. Prices are per 1,000 results.
Video, audio & social
- YouTube Transcript API — captions as timed segments, text, SRT or VTT, with language fallback and translation.
- YouTube Comments API — comments and replies with likes, pinned and hearted flags, newest or top sort.
- YouTube Channel API — a channel's videos, Shorts and live streams, plus YouTube search.
- Podcast Search, Episodes & Charts API — Apple Podcasts search, charts and full episode feeds.
- Bluesky Scraper — profiles, posts, followers and follows from the public AT Protocol API.
- Telegram Channel Scraper — posts, views and channel stats from public Telegram channels.
- Substack Scraper — posts with full free text, comments and publication profiles.
News, documents & the web
- Google News Search, Topics & Real Article URLs — news search and topic feeds with the publisher's real URL decoded.
- Website to Markdown — Content Extractor for LLMs & RAG — any site as clean Markdown, text and heading-aware chunks.
- Internet Archive API — archive.org search, item metadata, files and reviews.
- Wayback Machine Toolkit — archived URL inventories, snapshots and text diffs between dates.
- Domain Intelligence API — DNS, RDAP registration, TLS certificate and HTTP facts in one row per domain.
- SEO Page Audit — sitemap crawl with on-page checks, structured data and broken-link reports.
- Keyword Suggestions API — Google, YouTube, Bing, Amazon and eBay autocomplete with alphabet and question expansions.
- Website Contact Extractor — emails, phone numbers and social profiles from any list of websites.
Business, finance & jobs
- Congress & Insider Trades API — STOCK Act periodic transaction reports and SEC Form 4 insider trades in one schema.
- SEC EDGAR API — filings, XBRL financials and full-text search by ticker or CIK.
- Y Combinator Companies, Batches & Founders — the YC directory with founders and social links, filterable by batch, industry and hiring status.
- Career Site Jobs API — jobs straight from Greenhouse, Lever, Ashby, Workable and 10+ other ATS career sites.
- New Job Postings Monitor — new, closed and changed postings on the career sites you watch.
- Shopify Products API — any Shopify store's catalogue, variants, prices and stock signals.
Apps & games
- App Store & Google Play Reviews API — reviews from both stores with ratings, versions and developer replies.
- App Store Top Charts & App Search API — Apple top charts by country and genre, plus app search and details.
- Steam Reviews API — Steam reviews with playtime, helpfulness and game details.
- Steam Game Data API — prices, tags, review scores, live player counts and top charts.