Tech Stack Detector – 5,800 Technologies with Versions
Pricing
from $8.00 / 1,000 result delivereds
Tech Stack Detector – 5,800 Technologies with Versions
Tech stack detector for a list of websites: one plain HTTP request per page, no browser, and 5,800 technologies identified from the response - CMS, ecommerce, analytics, frameworks, hosting, CDN, payment and ad tech - with the version where the page reveals one. Pay only for pages that answer.
Pricing
from $8.00 / 1,000 result delivereds
Rating
0.0
(0)
Developer
Locomint
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
This tech stack detector tells you what any website runs. Paste a list of domains or URLs and get one row per site: the CMS, the ecommerce platform, the JavaScript framework, the analytics, the tag manager, the payment processor, the CDN, the web server and the hosting behind it - with the version number wherever the page reveals one.
It works from one plain HTTP request per page. No browser, no JavaScript engine, no login and no proxy. That is why it is fast, why a run of a thousand sites takes minutes rather than hours, and why it can be priced the way it is.
What it does
Every line of input becomes one page to read:
- A bare domain such as
shopify.comis read ashttps://shopify.com/. - A full URL such as
https://www.gymshark.com/is used as given. - Any deeper page such as
https://example.com/pricingworks too, and sometimes tells you more than the homepage - checkout and pricing pages carry payment and A/B testing tags that the front page does not.
Duplicates are removed, including the https://acme.com, https://acme.com/, https://ACME.com/
and https://acme.com/#top spellings of the same page, so a column pasted out of a spreadsheet is
charged once per site. Anything that is not a domain or a URL is named in the run log and skipped.
The page is then fetched once over a direct connection and matched against a fingerprint set of 7,610 technologies, of which 5,834 can be identified from a single plain response - 76.7%. Seven kinds of evidence are read out of that one request:
| Evidence | Examples of what it finds |
|---|---|
| Response headers | Nginx, Apache, Cloudflare, Fastly, Vercel, Varnish, HSTS, Amazon S3 |
| Cookies | Shopify, WooCommerce, Laravel, ASP.NET, session and consent platforms |
| Meta tags | Generator tags: WordPress and its version, Drupal, Joomla, Astro, Hugo, Gatsby |
| The markup | Bootstrap, Tailwind, Font Awesome, Elementor, theme and plugin paths |
| Inline scripts | Google Tag Manager containers, Segment, Hotjar, Klaviyo, chat widgets |
| Script URLs | Every hosted library, pixel, CDN and SaaS widget the page loads |
| The URL itself | Platform-hosted domains such as myshopify.com or squarespace.com |
On top of the direct matches, a technology's stated implications are expanded - WordPress implies PHP and MySQL - and its stated requirements are honoured, so a WooCommerce fingerprint on a page with no WordPress is not reported. That is most of the difference between a plausible answer and a credible one.
What is in a row
| Field | What goes in it |
|---|---|
url | The page that was fetched, normalised from what you typed. |
final_url | Where it ended up after redirects. Different from url means the site moved you. |
status | ok when technologies were found, no_match when the page was read and nothing matched. |
http_status | The HTTP status of the page that was scanned. Always under 400 - see below. |
tech_count | How many technologies are in this row. |
technologies | One object per technology: name, categories (one or more of 107), version or null. |
tech_names | The same findings as a flat list of proper names - ["WordPress", "Google Tag Manager"] - which is the column you want in a CSV. |
tech_slugs | The same findings as slugs - ["wordpress", "google-tag-manager"] - for joining against a table you already have. |
categories | The distinct categories present, most defining first - a CMS before a font library. |
scan_time_ms | Milliseconds from starting the fetch to finishing detection, for this page. |
fetched_at | ISO 8601 UTC, when the page was read. |
input | The line you typed, so a row can be matched back to your sheet. |
The category filter is free
Name one or more categories and only those technologies are reported - and a page with nothing in those categories is left out of the dataset entirely and is not charged for. So "every Shopify site in this list" costs you only the Shopify sites.
A real run of eight sites with categoriesFilter: ["CMS", "Ecommerce"] delivered four rows and
charged for four: Rolling Stone (WordPress 6.9.7), Allbirds (Shopify), Gymshark (Contentful and
Shopify) and TechCrunch (WordPress 6.9.7). Basecamp, Figma, Mozilla and Vercel run neither, so
they produced no row at all.
Spelling is matched case-insensitively against the real category list, and anything unrecognised is named in the run log rather than silently matching nothing.
A page that gives no answer costs nothing
Only a page that was actually read produces a row. Every one of these produces none, is counted and named in the run log with its reason, and costs you nothing:
| What happened | Why there is no row |
|---|---|
| The site did not answer, or refused the connection | There is nothing to report. |
| The site answered with an anti-bot challenge | The host is backed off from and never retried from another address. |
| The site answered HTTP 400 or worse | The headers of a 404 page would still name a CDN, but that is an answer about an error page, not about the site. |
| The URL was not a web page | A PDF, an image or an archive has no stack of its own; all a fingerprint set could find is the CDN serving the file. Brochure links turn up in most pasted lists. |
| The page did not answer inside the time limit | Reported with the limit that was in force. |
| The address failed the safety check | Loopback, private, link-local and cloud metadata addresses are refused. |
| Every technology was removed by your category filter | You asked not to see it. |
Who it is for
- Sales and business development qualifying accounts by what they already run - find the Shopify Plus stores, the HubSpot users, the sites still on a platform you replace.
- Agencies and consultancies auditing a prospect list before the pitch, or checking which of their own clients are still on an old CMS or an unpatched plugin version.
- Competitive and market research measuring platform share across an industry or a country: how many of these 2,000 retailers run Shopify, and how many moved this year.
- Recruiters and technical sourcers finding companies that use the stack a candidate knows.
- Security and compliance teams taking an inventory of a domain portfolio, including the version strings that say which sites are behind.
- Data and AI teams who want a typed technology dataset with a timestamp per row.
How to use it
In the Apify Console:
- Paste your sites into Websites to scan, one per line, up to 5,000 per run.
- Leave Include version numbers on unless you only want names.
- Optionally name the technology categories you care about. The filter is free.
- Start the run and export the dataset as CSV, Excel or JSON.
From the API, this call starts a run, waits for it and returns the rows:
curl -X POST \"https://api.apify.com/v2/acts/locomint~tech-stack-detector/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"urls": ["gymshark.com", "techcrunch.com", "https://stripe.com/"]}'
The synchronous endpoint waits up to 300 seconds. For a long list, start the run with
POST https://api.apify.com/v2/acts/locomint~tech-stack-detector/runs?token=YOUR_APIFY_TOKEN and
read its dataset when the run finishes. With the Python client (pip install apify-client):
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("locomint/tech-stack-detector").call(run_input={"urls": ["gymshark.com", "allbirds.com", "basecamp.com", "techcrunch.com"],"categoriesFilter": ["CMS", "Ecommerce"],"versions": True,})for row in client.dataset(run.default_dataset_id).iterate_items():print(row["url"], row["tech_count"], row["tech_names"])
Input example
{"urls": ["wordpress.org","www.gymshark.com","https://techcrunch.com/","https://www.python.org/"],"versions": true,"categoriesFilter": [],"concurrency": 5,"timeoutSeconds": 20}
| Field | Default | Allowed | What it does |
|---|---|---|---|
urls | required | 1 to 5,000 | Domains or URLs, one per line. Duplicates removed. |
versions | true | true / false | Report the version where the page reveals one. Same price either way. |
categoriesFilter | empty | any category names | Keep only these categories. Free: a page with none is not delivered and not charged. |
concurrency | 5 | 1 to 10 | Pages fetched at the same time. |
timeoutSeconds | 20 | 5 to 90 | A page with no answer by then is left out, and not charged. |
The 107 categories include CMS, Ecommerce, Analytics, JavaScript frameworks, Web frameworks, Web servers, CDN, Hosting, PaaS, IaaS, Payment processors, Buy now pay later, Tag managers, Marketing automation, CRM, Live chat, SEO, Advertising, Retargeting, Security, Cookie compliance, Email, Reviews, Page builders, WordPress plugins, WordPress themes, Shopify apps, Shopify themes, Databases, Programming languages, Static site generator, Reverse proxies, Caching, A/B Testing, Form builders, Appointment scheduling, Shipping carriers and Artificial Intelligence.
Output example
Two real rows from a run on 12 September 2026.
{"url": "https://techcrunch.com/","final_url": "https://techcrunch.com/","status": "ok","http_status": 200,"tech_count": 12,"technologies": [{ "name": "WordPress", "categories": ["CMS", "Blogs"], "version": "6.9.7" },{ "name": "WordPress Block Editor", "categories": ["Page builders"], "version": null },{ "name": "MySQL", "categories": ["Databases"], "version": null },{ "name": "PHP", "categories": ["Programming languages"], "version": null },{ "name": "Nginx", "categories": ["Web servers", "Reverse proxies"], "version": null },{ "name": "WordPress VIP", "categories": ["PaaS"], "version": null },{ "name": "Yoast SEO", "categories": ["SEO", "WordPress plugins"], "version": "25.1" },{ "name": "Yoast SEO Premium", "categories": ["SEO"], "version": "25.1" },{ "name": "Google Tag Manager", "categories": ["Tag managers"], "version": null },{ "name": "HSTS", "categories": ["Security"], "version": null },{ "name": "reCAPTCHA", "categories": ["Security"], "version": null },{ "name": "Sailthru", "categories": ["Marketing automation", "Email", "Personalisation"], "version": null }],"tech_names": ["WordPress", "WordPress Block Editor", "MySQL", "PHP", "Nginx", "WordPress VIP", "Yoast SEO", "Yoast SEO Premium", "Google Tag Manager", "HSTS", "reCAPTCHA", "Sailthru"],"tech_slugs": ["wordpress", "wordpress-block-editor", "mysql", "php", "nginx", "wordpress-vip", "yoast-seo", "yoast-seo-premium", "google-tag-manager", "hsts", "recaptcha", "sailthru"],"categories": ["CMS", "Blogs", "Page builders", "Databases", "Programming languages", "Web servers", "Reverse proxies", "PaaS", "SEO", "WordPress plugins", "Tag managers", "Security", "Marketing automation", "Email", "Personalisation"],"scan_time_ms": 551,"fetched_at": "2026-09-12T15:21:42+00:00","input": "techcrunch.com"}
An online shop, where the interesting part is that the storefront and the content system are two different products:
{"url": "https://www.gymshark.com/","status": "ok","http_status": 200,"tech_count": 11,"tech_names": ["Contentful", "Next.js", "Shopify", "Algolia", "Afterpay", "Amazon Web Services", "React", "Amazon CloudFront", "HSTS", "Linkedin Insight Tag", "Webpack"],"categories": ["CMS", "JavaScript frameworks", "Web frameworks", "Web servers", "Static site generator", "Ecommerce", "Search engines", "Payment processors", "Buy now pay later", "PaaS", "CDN", "Security", "Analytics", "Miscellaneous"],"scan_time_ms": 465}
Versions read off a run of 31 well-known sites the same day: WordPress 7.2, WordPress 7.1, WordPress 6.9.7, Yoast SEO 27.3, Yoast SEO 25.1, jQuery 1.8.2, jQuery UI 1.12.1, Astro 6.3.7, Nginx 1.27.5 and Sentry 9.12.0. A version appears when the page publishes one; most technologies never do.
Pricing
| Event | Price |
|---|---|
| Page scanned (one dataset row) | $0.01, which is $10.00 per 1,000 pages |
| Actor start | $0.00005 per GB of run memory, charged once per run |
Worked example: a list of 2,000 domains where 1,850 answer is 1,850 x $0.01 = $18.50 plus one start event. Users on paid Apify plans pay less per page.
You pay only these event prices; Apify compute is not billed to you separately. Pages that did not answer, were refused, timed out, answered with a challenge, answered HTTP 400 or worse, were not a web page, or were removed by your category filter produce no rows and cost nothing. If you set a maximum cost per run, nothing above it is ever charged: the rows that would have passed it are not delivered, the run stops rather than reading pages nobody will be shown, and the log says how many pages were scanned but left out so a short dataset is never mistaken for sites that failed.
FAQ
Does this need a browser?
No, and that is deliberate. Everything comes out of one ordinary HTTP request: the response headers, its cookies, the meta tags, the markup, the inline scripts and the script URLs. A headless browser per site would be slower by an order of magnitude and would cost more to run than this listing sells for. The trade is in Limits below, stated plainly.
How many technologies can it find?
The fingerprint set indexes 7,610. 5,834 of them - 76.7% - are reachable from a single plain response, and that is the number this actor works with. The rest need a live JavaScript environment, a DNS or certificate lookup or a second request, and are not attempted.
Where do the versions come from?
From the page itself: a generator meta tag, a query string on an asset (?ver=6.9.7), a
fingerprinted file path, a header. Nothing is guessed or inferred from release dates. In a run of
31 well-known sites, 7 of them carried at least one version - about one row in four - and
WordPress sites carried the most, because WordPress and its plugins publish theirs.
Why did a big brand's site come back with no row?
Some large consumer sites answer a datacenter connection with an anti-bot challenge. This actor does not work around that: the host is backed off from, never retried through another address, and reported in the run log. You are not charged. In a test of 40 well-known sites, 31 answered normally, 7 answered with a challenge and 2 did not answer in time.
Can I scan a page other than the homepage?
Yes. Pass any URL. Product, pricing and checkout pages often reveal payment processors, A/B testing tools and personalisation platforms that the homepage does not load.
Is a page with nothing detected still charged?
Yes - it is a real answer, and status says no_match so you can filter it out. It is rare: a
server header alone is usually a match, and in a run of 31 well-known sites it did not happen once.
If you only want pages that run something specific, use the category filter, which is free.
How fast is it?
A quarter of a second to two and a half seconds per page, and it is nearly all network: measured on real pages, the matching itself took 11 ms on a 51 KB page, 52 ms on a 358 KB one and 176 ms on a 1.6 MB one. A run of 40 well-known sites at eight in parallel finished in 10 seconds, 5 of them spent fetching and matching, and used 115 MB of memory.
Does it respect a site's wishes?
It never works around a refusal. One page per URL, fetched as an ordinary browser-like client at a browser's pace; a site that answers with a challenge or a rate limit is left alone rather than retried from another address, and that row costs you nothing. Business owners can ask to be left out entirely, and every run reads that removal list before it starts - a domain on it is never requested at all.
It does not read /robots.txt. You are handing it a list of pages you already mean to look at,
one fetch each, and what comes back is what any visitor's browser would be served. Those rules
are written for crawlers that follow links across a site; this actor follows none, and crawls
nothing. Whether that suits your work is yours to judge, and the Limits section states it
plainly so that you can.
Limits
- JavaScript-only signals are not detected. About 1,776 of the 7,610 technologies - roughly a quarter - are only identifiable from a running JavaScript environment, intercepted network traffic, a DNS or certificate lookup, or an extra request. Those fingerprints are skipped rather than guessed at. In practice this mostly costs you tools that load themselves late through a tag manager, and some single-page applications that render everything in the browser.
- External JavaScript files are not downloaded and read. A technology whose only trace is inside a bundle it fetches will not appear.
- One page per URL. Nothing is crawled, and no second page is fetched.
- 5,000 URLs per run, 90 seconds per page at most, 10 pages at a time at most.
- The first 2 MB of a page is scanned. Almost nothing real is longer.
- The first 250 script tags and 250 meta tags on a page are read. The heaviest page in a 40-site sample carried 107 script tags, so this is a ceiling against a page built to be expensive rather than a limit a real site meets.
- A detection is evidence that something is present, not proof that it is in use. A leftover script tag looks the same as a live one.
- Absence is weaker than presence: "no analytics found" can mean a tool loaded later in the browser, not that the site has none.
- Nothing is cached between runs. Each run reports what the page served at that moment, which is
also why
fetched_atis on every row. - Datacenter connections only. There is no proxy option and no browser option.
- robots.txt is not read. Every URL you pass is fetched, including one whose path a site's robots.txt would tell a crawler to leave alone. Nothing is crawled and no link is followed, so the only pages touched are the ones in your input - but if your work requires those rules to be applied, apply them to your list before you send it.
Attribution
Technology detection uses the open fingerprint set from enthec/webappanalyzer (GPL-3.0), pinned to a commit. Locomint runs it server-side and returns results rather than redistributing the data. A small number of additional signatures are maintained by Locomint.
Compliance
Rows are about websites, not people. No field holds a person's name, email address or profile, and nothing is collected beyond what the page serves to any visitor. A site that answers with a challenge or a block is not worked around. You are responsible for using the results lawfully.
Questions, bug reports and feature requests go on this actor's Issues tab. Business owners can send data-removal requests to info@locomint.io; that address is for removal requests only. This actor keeps no copy of what it reads between runs.
Other Locomint actors
- Google Maps Scraper & Email Extractor – Business Leads: Search terms and a city in, business records with website contacts out.
- Google Maps Scraper – Multi-City Lead Lists with Emails: Many categories across many cities in one deduplicated run.
- Google Maps Place Details Scraper – Bulk Place ID Lookup: Place IDs or place-page links in, full records out.
- Website Email Scraper – Contact Details, Socials & WhatsApp: Contact points from website URLs you supply.
- Website Content Crawler – Markdown for AI, Emails & Contacts: A whole site as Markdown, with its contact points.
- Bulk Email Verifier & Validator: Checks whether addresses can receive mail.
- Company Enrichment API – Domain to Emails, Socials & Tech: A domain in, its contacts and technologies out.
- AI Crawler Checker – robots.txt Rules for GPTBot & ClaudeBot: Which AI crawlers a site's robots.txt allows.
- Schema Markup Validator & Generator – JSON-LD Checker: Checks and generates schema.org markup.
- Career Site Job Scraper – Greenhouse, Lever, Ashby, Workable: Open vacancies straight from an employer's own job feed.