Tech Stack Detector (Apify Actor)

Find the CMS, framework, analytics and CDN of any website list for a flat $2 per 1,000 sites, with evidence per detection. No API key, unreachable URLs free, set a max spend. Runs as an Apify Actor, callable from MCP clients via the Apify MCP server (https://mcp.apify.com/?actors=pennydata/website-tech-stack-detector).

Hosted MCP Server

npx add-mcp 'https://mcp.apify.com/?actors=pennydata/website-tech-stack-detector'

Installs into Claude Code, Codex, Cursor and more

Documentation

Tech Stack Detector - Website CMS, Framework & Analytics (pennydata/website-tech-stack-detector) Actor

Tech stack detector: paste website URLs, get one row each: CMS (WordPress, Shopify...), frameworks, server/CDN, analytics, with evidence. $0.002 per site, unreachable URLs free. Click Start: the 3 prefilled sites cost $0.006.

Pricing

from $1.40 / 1,000 url analyzeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events. Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes. In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours, and optionally produces a well-defined JSON output, datasets with results, or files in key-value store. In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects. You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the API section below.

Each client library has reference documentation the quickstart does not restate: JavaScript/TypeScript (npm install apify-client) and Python (pip install apify-client).

README

Tech Stack Detector & Change Monitor - Wappalyzer Alternative

Tech stack detector: paste website URLs, click Start, and get each site's CMS, framework, analytics and CDN with the evidence for every detection. $2 per 1,000 sites ($0.002 per site), failed URLs free, no API key, one plain HTTP request per site. The 3 prefilled sites (wordpress.org, shopify.com, github.com) run as is in about 20 seconds and cost $0.006. A Wappalyzer and BuiltWith alternative: every detection lists its header, meta tag, script URL or cookie name.

Example input (the form opens with this prefill; click Start):

{"urls":[{"url":"https://wordpress.org"},{"url":"https://www.shopify.com"},{"url":"https://github.com"}]}

Sample output (real run, 2026-10-22, 3 sites, 3 url-analyzed events = $0.009):

inputhttpStatustechnologies found
https://wordpress.org200WordPress, Google Tag Manager, Nginx
https://www.shopify.com200Cloudflare
https://github.com200Contentful, GitHub (hosting)

Detects WordPress, Shopify, Magento, Next.js, Cloudflare, Google Analytics and about 60 more.

Free to try: a new Apify account includes free monthly platform credit, enough to validate the output on a few dozen sites before you pay anything. This Actor has no hidden minimums: failed items are never billed.

Try it (no code)

Open the Store page and click Try for free. The input form opens with the schema prefill, three sites (https://wordpress.org, https://www.shopify.com, https://github.com), so Start runs as-is. There is no URL parameter that pre-fills custom input; paste your own URLs into urls instead.

Sample output of a real local run on 3 sites (2026-10-22, 3 rows, 3 url-analyzed events):

inputhttpStatustechnologies found
https://wordpress.org200WordPress, Google Tag Manager, Nginx
https://www.shopify.com200Cloudflare
https://github.com200Contentful, GitHub (hosting)

Example output (real run, 2026-10-20)

Input https://wordpress.org, one row, one url-analyzed event:

{
  "input": "https://wordpress.org",
  "finalUrl": "https://wordpress.org",
  "httpStatus": 200,
  "totalTechnologies": 3,
  "categories": {"CMS": ["WordPress"], "Tag manager": ["Google Tag Manager"], "Web server": ["Nginx"]},
  "technologyNames": ["WordPress", "Google Tag Manager", "Nginx"],
  "technologies": [
    { "name": "WordPress", "category": "CMS", "evidence": "meta generator \"WordPress 7.2-alpha-64584\"" },
    { "name": "Google Tag Manager", "category": "Tag manager", "evidence": "html GTM noscript iframe" },
    { "name": "Nginx", "category": "Web server", "evidence": "header server" }
  ],
  "capturedAt": "2026-10-20T04:38:05.293Z"
}

Quickstart (one API call)

curl -X POST "https://api.apify.com/v2/acts/pennydata~website-tech-stack-detector/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls":[{"url":"https://wordpress.org"}]}'

Or open the Actor in the Console and click Start: the prefilled input (three sites) runs as-is. A BuiltWith / Wappalyzer alternative you pay for per URL, not per month.

How to use Website Tech Stack Detector

  1. Paste public URLs or bare domains into urls.
  2. Leave respectRobotsTxt on unless you are entitled to switch it off.
  3. Click Start.
  4. Use technologyNames for quick filtering or technologies for category and evidence.

Coming from magicfingers/techstack-detector? Your existing input works unchanged (urls, navigationTimeoutSecs, maxConcurrency, checkHeaders and the other options are accepted).

Drop-in compatible with misterkhan/website-tech-stack-scanner input (startUrls) and motivational_nickel/website-technology-detector input (urls, verify_ssl).

Also accepted: startUrls (request-list objects like {"url": "https://example.com"} or plain strings), websites (list of domains or URLs), url (single URL) and domains (list), all same as urls. Every row has status (ok or error, with error text); a SUMMARY record in the key-value store counts total, ok, error and charged URLs. Only ok rows are charged.

Monitor competitor tech changes

Run the Actor on a list of competitor or prospect domains, note the run's default dataset ID, then run it again later (or on a weekly schedule) with that ID in compareToDatasetId. Every site then carries added and removed technology names versus the earlier run, so you see a new checkout platform, a dropped analytics tool or a CDN migration without comparing lists by hand. Sites missing from the earlier dataset get previousFound: false. The diff adds no extra charge.

{ "urls": ["https://example.com"], "compareToDatasetId": "<dataset ID of the previous run>" }

Pricing

Pay per event, no subscription and no compute fees on top. Price: $2 per 1,000 sites ($0.002 per URL).

EventWhen it is chargedPrice
url-analyzedOne website URL fetched successfully (HTTP below 400) and analyzed for technologies.$0.002

Failed, blocked or unknown items are not billed. Paid Apify plans get volume discounts down to $0.0014 per URL. Set a maximum cost per run in the run options to cap spend.

Example input

{
  "urls": [
    {
      "url": "https://nextjs.org"
    }
  ],
  "respectRobotsTxt": true
}

Check client sites for known-vulnerable versions (CVE exposure)

For MSPs and web agencies auditing client sites: set checkCves to true and each item gets the known CVEs for the technology versions the site itself exposes (WordPress and Drupal/Joomla via the meta generator tag, jQuery and Bootstrap via the versioned script file name, Nginx/Apache via the Server header, PHP via X-Powered-By). Lookups use the free NIST NVD CVE API 2.0 by exact CPE name, one request per product+version per run (cached), spaced to respect NVD's public rate limit. There is no extra charge: the price stays $0.002 per site.

{
  "urls": ["https://www.python.org", "https://client-site.example"],
  "checkCves": true
}

Added fields per item: cves (up to 25, highest CVSS first: id, cvssScore, severity, published, technology, version), cveCount (total found) and maxSeverity. Each entry in technologies also carries a version when the site states one.

{ "input": "https://www.python.org", "maxSeverity": "MEDIUM", "cveCount": 6,
  "cves": [{ "id": "CVE-2020-11022", "cvssScore": 6.9, "severity": "MEDIUM", "published": "2020-04-29T22:15:11.903", "technology": "jQuery", "version": "1.8.2" }] }

Honest limits: only versions the page reveals are checked (many sites hide them); a CVE listed for a version does not prove the site is exploitable (backported patches, mitigations), so treat it as a triage list. NVD without a key allows about 5 requests per 30 s, so large lists are slower; add the optional free nvdApiKey to go about 10x faster. Data is NVD's, this actor is not affiliated with or endorsed by NIST.

Details and limits

Give it a list of public website URLs and get back the technologies each site appears to use: CMS, ecommerce platform, analytics and tag managers, CDN and hosting, web server, JS frameworks and libraries, payments, cookie-consent tools. It makes one plain HTTP request per site (no browser), so runs are fast and cheap.

What it does

  • Input: a list of public http(s) URLs (bare domains such as example.com are accepted and fetched over https).
  • For each URL it fetches the page once (following up to 5 redirects) and inspects only:
    • response headers (server, x-powered-by, cf-ray, x-vercel-id, ...),
    • HTML meta tags (<meta name="generator">),
    • script src URLs and well-known HTML markers (for example __NEXT_DATA__, /wp-content/),
    • cookie names from Set-Cookie (names only; cookie values are never read or stored).
  • Output per URL: input, finalUrl, httpStatus, technologyNames (flat list), totalTechnologies (integer count), categories (object grouping names by category, e.g. {"CMS": ["WordPress"], "Analytics": ["Google Tag Manager"]}) and technologies (name, category, and the evidence that triggered it), capturedAt.
  • Lead list: the run's key-value store also holds leads-by-tech.csv (columns technology, category, site url, evidence, sorted by technology) so you get every Shopify, WordPress or HubSpot site in one list, and the SUMMARY record has technologyCounts (sites per technology).
  • About 60 technologies are recognised, e.g. WordPress, Shopify, WooCommerce, Magento, Wix, Squarespace, Webflow, Drupal, Next.js, Nuxt, React, Vue.js, Angular, Cloudflare, CloudFront, Fastly, Vercel, Netlify, Google Analytics, Google Tag Manager, Meta Pixel, Hotjar, Stripe.

Limits and honesty notes

  • Detection is based on one HTTP request to the URL you give, with no JavaScript execution. Technologies that only show up after client-side rendering, or on other pages of the site, can be missed. A site with no visible signals returns an empty list; that does not prove nothing is used.
  • Detection is signature-based and can produce false positives or negatives (for example a CDN header that only reflects a proxy in front of the site, or a site that hides its headers). Treat results as strong hints, not an audit. No version numbers are reported.
  • Only the first 1 MB of each page is inspected.
  • robots.txt is respected by default (the wildcard * group; switch off with respectRobotsTxt: false only for sites you are entitled to analyze). The actor identifies itself with the user agent TechStackDetectorBot.
  • Only public http(s) URLs: localhost, private and link-local IP ranges, and non-http schemes are rejected, and every redirect hop is re-checked.
  • Sites behind bot walls, logins or captchas may return an error page or a block status; no proxies, no captcha solving and no evasion are used.
  • You are responsible for having the right to analyze the URLs you submit. The actor collects no personal data: only technology signals are extracted, and cookie values are discarded.

Switching from another tech-stack actor

Saved tasks and API calls written for other tech-stack actors run here with only the actor ID changed. Input names checked on 2026-10-21 against the public input schemas of the two most-used rivals, nexgendata/wappalyzer-replacement (about 1,500 users) and automation-lab/tech-stack-detector (about 390 users). This Actor is independent and not affiliated with either.

Their inputHere
urls (plain strings or objects)urls, same
startUrls, domains, websites, urlsame names, accepted
targetUrlsaccepted as an alias of urls
timeout_secondsalias of timeoutSecs
verify_sslaccepted and ignored
categories_filter, include_confidence, include_versionsaccepted and ignored (not supported; a log line names them). Every detection already lists its evidence; filter by categories in the output

Output fields differ (technologyNames, categories, technologies with evidence), so check your downstream mapping. Pricing is on the Pricing section above; compare it with your current actor before switching.

Use from Claude, Cursor or any MCP client

Apify's MCP server can expose this actor as a tool. Use this URL (format from the Apify MCP docs, ?tools= takes a comma-separated list of actors):

https://mcp.apify.com/?tools=pennydata/website-tech-stack-detector

Client config (mcpServers format; sign in with OAuth when the client asks):

{"mcpServers": {"apify": {
  "url": "https://mcp.apify.com/?tools=pennydata/website-tech-stack-detector"
}}}

Example prompt: "Which CMS and analytics tools does example.com use?"

Related actors

FAQ

How accurate is it?
Signature-based on one HTTP request without JavaScript execution, so client-rendered or hidden technologies can be missed. Treat results as strong hints, not an audit.

Is it legal?
It requests only the URL you provide, respects robots.txt by default, stores no cookie values and no personal data.

Need a custom field, a higher volume or a different source?
Open an issue on the Actor page and describe what you need; custom variants are possible.

Is it maintained?
Yes. Reports of breakage are answered through the Issues tab, and runs that fail are not billed.

Built with AI assistance (Claude); maintained by the publisher.

Use cases

  • Qualify sales leads by the CMS, ecommerce platform or analytics tool they use.
  • Build agency prospect lists, for example every Shopify or WordPress site in a list.
  • Competitor research: see which CDN, framework or tag manager rivals run.
  • Migration audits: find sites still on a legacy platform.

I built this and earn from its runs. Written with AI assistance (Claude).

Actor input Schema

url (type: string):

Alias for a single URL; same as putting it in "urls".

domains (type: array):

Alias: list of bare domains or URLs, analyzed together with "urls".

urls (type: array):

Public http(s) pages to analyze (bare domains like example.com are accepted). Aliases: "url" (single) and "domains" (list) are also accepted.

startUrls (type: array):

Alias for "urls": request-list objects ({"url": ...}) or plain strings, analyzed together with "urls".

websites (type: array):

Alias: list of websites (bare domains or URLs), analyzed together with "urls".

targetUrls (type: array):

Alias for "urls" (same field name as other tech-stack actors): bare domains or URLs, analyzed together with "urls".

compareToDatasetId (type: string):

Optional. Dataset ID of an earlier run of this Actor. Each site then gets added[] and removed[] technologies versus that run (previousFound=false if the site was not in it). Use with a weekly schedule to monitor competitor tech changes.

checkCves (type: boolean):

For technologies whose version the site exposes (WordPress, Drupal, Joomla, jQuery, Bootstrap, Nginx, Apache, PHP), look up known CVEs in the free NIST NVD API and add cves, cveCount and maxSeverity to each item. Same price per site. Slower: NVD allows about 5 requests per 30 s without a key.

nvdApiKey (type: string):

Optional free key from nvd.nist.gov/developers/request-an-api-key; raises the NVD rate limit about 10x.

respectRobotsTxt (type: boolean):

Skip URLs disallowed for all bots in the site's robots.txt (skipped URLs are not charged).

maxConcurrency (type: integer):

Maximum number of sites analyzed in parallel (1-20).

timeoutSecs (type: integer):

Per-request timeout in seconds (5-60). Alias: "timeout_seconds".

timeout_seconds (type: integer):

Alias for "timeoutSecs".

verify_ssl (type: boolean):

Accepted so inputs saved for motivational_nickel/website-technology-detector run unchanged. Not used.

navigationTimeoutSecs (type: integer):

Alias for "timeoutSecs", accepted so inputs saved for magicfingers/techstack-detector run unchanged. "timeoutSecs" wins when both are set.

waitForSecs (type: integer):

Accepted so inputs saved for magicfingers/techstack-detector run unchanged. Not used: headers, cookies, DNS and page content are always checked.

checkHeaders (type: boolean):

Accepted so inputs saved for magicfingers/techstack-detector run unchanged. Not used: headers, cookies, DNS and page content are always checked.

checkCookies (type: boolean):

Accepted so inputs saved for magicfingers/techstack-detector run unchanged. Not used: headers, cookies, DNS and page content are always checked.

checkDns (type: boolean):

Accepted so inputs saved for magicfingers/techstack-detector run unchanged. Not used: headers, cookies, DNS and page content are always checked.

checkRobotsTxt (type: boolean):

Accepted so inputs saved for magicfingers/techstack-detector run unchanged. Not used: headers, cookies, DNS and page content are always checked.

proxyConfiguration (type: object):

Accepted so inputs saved for similar tech-stack Actors run unchanged. Not used.

Actor input object example

{
  "urls": [
    {
      "url": "https://wordpress.org"
    },
    {
      "url": "https://www.shopify.com"
    },
    {
      "url": "https://github.com"
    }
  ],
  "checkCves": false,
  "respectRobotsTxt": true,
  "maxConcurrency": 5,
  "timeoutSecs": 20
}

Actor output Schema

results (type: string):

No description

API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

JavaScript example

import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        {
            "url": "https://wordpress.org"
        },
        {
            "url": "https://www.shopify.com"
        },
        {
            "url": "https://github.com"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pennydata/website-tech-stack-detector").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`πŸ’Ύ Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// πŸ“š Want to learn more πŸ“–? Go to β†’ https://docs.apify.com/api/client/js/docs

Python example

from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "urls": [
        { "url": "https://wordpress.org" },
        { "url": "https://www.shopify.com" },
        { "url": "https://github.com" },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("pennydata/website-tech-stack-detector").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"πŸ’Ύ Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# πŸ“š Want to learn more πŸ“–? Go to β†’ https://docs.apify.com/api/client/python/docs/quick-start

CLI example

echo '{
  "urls": [
    {
      "url": "https://wordpress.org"
    },
    {
      "url": "https://www.shopify.com"
    },
    {
      "url": "https://github.com"
    }
  ]
}' |
apify call pennydata/website-tech-stack-detector --silent --output-dataset

MCP server setup

{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pennydata/website-tech-stack-detector"
        }
    }
}

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an Authorization: Bearer <APIFY_API_TOKEN> header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/HL497t83rI9fiLzLM/builds/iJ7fYd2thgpFWjgjo/openapi.json