# Website Technology Stack Detector (`asunoki/tech-stack-detector`) Actor

Detect the CMS (WordPress, Shopify), CDN, hosting, DNS provider, analytics, payment and chat tools of each website in a list. One JSON row per domain, with evidence and a confidence score per detection. For lead-list enrichment, audits and AI agents (API, MCP). Pay only for successful scans.

- **URL**: https://apify.com/asunoki/tech-stack-detector.md
- **Developed by:** [Seisuke Nagahara](https://apify.com/asunoki) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 basic scans

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Website Technology Stack Detector

A bulk **website technology detector** for lists of domains. Give it a list of websites and it returns one JSON row per site with the **CMS** (WordPress, Wix, Squarespace and others), the **e-commerce platform** (Shopify, WooCommerce), JavaScript frameworks, analytics and tag managers, advertising tags, **CDN**, **hosting**, **DNS provider**, e-mail provider, **payment** providers and **live-chat** tools. It works as a tech stack detector and website technology scanner for lead lists, agency audits and AI agents. **Every detection comes with its evidence** (the response header, meta tag, script URL, cookie name or DNS record that triggered it) and a **confidence score**, so you can check *why* something was reported.

It is an independent technology detection engine with its own rule set (148 technologies in 24 categories), written from vendor documentation and public observation of vendors' own sites. Each rule stores its source URL, source type, confidence and last-verified date.

### What you get in one run

One flat row per website, with the fields below. Every detection carries a **confidence score** and the **evidence** that triggered it, so a sales or audit team can see *why* a technology was reported and filter out weak guesses with `minConfidence`.

| You want to know | Read this field |
|---|---|
| Which CMS the site runs (WordPress, Wix, Webflow, …) | `cms` |
| Whether it is a Shopify or WooCommerce store | `ecommercePlatform` |
| Which CDN, hosting platform and DNS provider it uses | `cdn`, `hosting`, `dnsProvider` |
| Which payment providers and live-chat tools it uses | `paymentProviders`, `chatSupport` |
| Analytics, tag managers and advertising tags | `analytics`, `tagManagers`, `advertising` |
| JavaScript frameworks and libraries | `frameworks`, `javascriptLibraries` |
| Every detection with its confidence (1–99) and evidence | `technologies[]`: `name`, `category`, `confidence`, `evidenceStrength`, `evidence[]` |

### Typical uses

- **Lead qualification (bulk technology analysis):** from a list of company domains, keep the ones that run Shopify with Klaviyo, use OneTrust, or have no tag manager. Sort and filter on the flat summary columns.
- **Lead-list enrichment:** add the CMS, e-commerce platform, CDN, hosting and DNS provider of each company to a list of domains, then download the dataset as CSV, JSON or Excel from Apify.
- **Agency and consultant audits:** which analytics, tag-manager, consent, CDN and hosting tools a client or competitor list uses, in one run.
- **Sales-trigger research:** which sites use a given CMS, framework, hosting or e-mail provider, so you can target a migration or integration offer.
- **AI agents and pipelines:** a structured answer to "what is this site built with?" with verifiable evidence, through the API or MCP.

### Quick start

```json
{ "urls": ["python.org", "kubernetes.io", "nodejs.org"], "minConfidence": 65 }
```

Start the Actor with that input (or paste your own list, one domain per line). A run of a few dozen domains takes seconds. You pay only for sites that were scanned successfully.

### Where this Actor fits

It is a **curated** detector: 148 technologies chosen for lead and audit work, each rule with a recorded source. It does not try to be an encyclopedia. If you need the longest possible technology catalogue, pick a tool that advertises thousands of signatures; if you need results you can **check**, with evidence and honest blocked/failed rows that are not billed, this Actor is built for that.

### HTTP scan and Full scan

| | **HTTP scan** (default) | **Full scan** (optional) |
|---|---|---|
| How | One page request, plus DNS and TLS lookups. No browser. | The page is rendered in headless Chromium. |
| Input setting | default | `browserFallback: true` (only pages that return a thin JavaScript shell) or `alwaysUseBrowser: true` (every page) |
| Speed | about 2–4 seconds per site on average | about 10–30 seconds per page, at most 2 pages at a time |
| Sees | HTML, response headers, cookies set by the server, script/link URLs, DNS, TLS | Everything above **plus** technologies loaded by JavaScript at runtime (for example analytics loaded through a tag manager) |
| Billing | Basic scan event | Full scan event, only for pages that were actually rendered |

Use the HTTP scan for large lists. Switch on the browser only where you need runtime-loaded technologies: it is slower and costs more per page. If the browser step fails on a site, you get the plain-HTTP result, billed as a Basic scan, and `browserError` says why.

### Input

| Field | Default | Description |
|---|---|---|
| `urls` | – | **Bulk input**: one domain or URL per line, up to 10,000. `https://` is assumed when missing. Duplicates are removed. |
| `browserFallback` | `false` | Render pages that return only a thin JavaScript shell. Slower, Full scan price for those pages. |
| `alwaysUseBrowser` | `false` | Render every reachable page. Slowest, Full scan price for every rendered page. |
| `respectRobotsTxt` | `true` | Skip pages the site's robots.txt disallows for this Actor (user agent `TechStackDetector`) or for all bots. See below. |
| `minConfidence` | `0` | Drop detections below this confidence (1–99). Values of 65–70 keep only detections backed by direct evidence. |
| `includeEvidence` | `true` | Return the signal behind each detection. |
| `includeDns` / `includeTls` | `true` | DNS records (name servers, MX, SPF) and the TLS certificate issuer/expiry. |
| `maxConcurrency` | `10` | Sites scanned in parallel (never two requests to the same host at once). |
| `timeoutSecs` | `20` | Time limit per site. |

### Output

One dataset row per input URL:

| Field group | Examples |
|---|---|
| Status | `scanStatus` (`ok` / `blocked` / `error` / `skipped_robots`), `statusCode`, `errorType`, `blockReason`, `scanMode`, `browserUsed`, `browserError` |
| Page | `finalUrl`, `title`, `description`, `language`, `redirects` |
| Detections | `technologies[]` with `name`, `category`, `confidence` (1–99), `evidenceStrength` (`strong` / `weak`), optional `version`, and `evidence[]` |
| Flat summary | `cms`, `ecommercePlatform`, `frameworks`, `javascriptLibraries`, `analytics`, `advertising`, `tagManagers`, `cdn`, `hosting`, `paymentProviders`, `marketingTools`, `chatSupport`, `emailInfrastructure`, `emailServices`, `dnsProvider`, `securityTools`, `consentManagement`, `fonts`, `maps`, `video`, `abTesting` |
| Infrastructure | `server`, `poweredBy`, `tlsIssuer`, `tlsValidTo`, `dns`, `headers`, `cookies` (names only), `scripts` |

Example row (shortened):

```json
{
  "url": "https://example-shop.com",
  "scanStatus": "ok",
  "ecommercePlatform": "Shopify",
  "analytics": ["Google Analytics"],
  "tagManagers": ["Google Tag Manager"],
  "technologyCount": 6,
  "technologies": [
    {
      "name": "Shopify", "category": "Ecommerce", "confidence": 90, "evidenceStrength": "strong",
      "evidence": [{ "method": "cookie", "rule": "shopify#2", "value": "(cookie name)", "confidence": 90, "strength": "strong" }]
    },
    {
      "name": "Mailgun", "category": "Email service", "confidence": 60, "evidenceStrength": "weak",
      "evidence": [{ "method": "dns_txt", "rule": "mailgun#1", "confidence": 60, "strength": "weak", "note": "SPF include shows a sender is authorized for the domain; it does not prove the service is currently used" }]
    }
  ]
}
```

#### Confidence and evidence strength

- `strong` evidence is a direct signal: a vendor-specific response header, a `generator` meta tag, a script or stylesheet actually loaded from a vendor host, an MX record of a mailbox provider.
- `weak` evidence is an inference: an SPF `include:` (a sender is *authorized*, not necessarily used), a `preconnect` hint, a URL that appears only inside inline script text, or a cookie name on its own. A detection that rests only on weak evidence is never reported above confidence **60** (75 with two independent weak signals).
- Confidence is a signal-strength score, not a probability.

### Blocked pages, robots.txt and what cannot be detected

- **Some sites cannot be scanned.** Pages behind bot protection (Cloudflare challenge, Akamai, DataDome, Imperva, HTTP 403/429) are reported as `blocked` with the reason. The Actor does **not** try to get past them: no CAPTCHA solving, no stealth or evasion techniques, no proxy rotation. On a list of large, well-known brand sites, about 28 of every 100 rows came back `blocked`, timed out, failed to resolve or were skipped, so expect gaps on such lists.
- **robots.txt is respected by default.** The Actor reads a host's `/robots.txt` once and skips a page if the rules disallow it for the user agent `TechStackDetector` or for all bots. Skipped pages are returned as `skipped_robots`. A missing robots.txt (4xx) allows scanning; a server error (5xx) is treated as disallow (RFC 9309). You can switch `respectRobotsTxt` off, but only do so for sites you own or have permission to scan; that choice and its consequences are yours.
- **Not billed:** `blocked`, `skipped_robots` and `error` rows. Only successfully scanned pages are billed.
- **Absence is not proof of absence.** The HTTP scan cannot see technologies that are only loaded by JavaScript after the page renders, that run purely on the server without any public trace, or that a site loads only after you accept cookies. Sites can also remove generator tags and hide asset paths.
- **Coverage is limited to the 148 technologies listed below.** A technology that is not in the list will not be reported.
- **Bare domains:** if a bare domain fails at the network level (no DNS record, connection refused or TLS failure), the Actor tries the `www.` host once.

#### Accuracy check

We compared results with facts that site owners and service providers publish themselves (privacy/cookie policies, developer documentation, public source repositories, customer case studies) for 31 sites and 44 documented facts. Every detection that could be checked this way was correct (27 of 27 with the HTTP scan, 32 of 32 with the Full scan), and the scans found 65% (HTTP) and 78% (Full scan) of the documented technologies; the misses were mostly technologies that load at runtime, load only after cookie consent, or leave no public trace. Only about one detection in five could be checked against an official statement, so read this as a sanity check on a small, non-random sample, not as a benchmark or a guarantee.

### Use it from the API

Run a scan and get the results in one call (synchronous calls time out after 300 seconds, so send batches of about 100–200 domains for the HTTP scan and fewer than 40 for browser modes, or start an asynchronous run for larger lists):

```bash
curl -X POST "https://api.apify.com/v2/acts/asunoki~tech-stack-detector/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <YOUR_APIFY_TOKEN>" -H "Content-Type: application/json" \
  -d '{"urls": ["python.org", "kubernetes.io"], "minConfidence": 65}'
```

```python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("asunoki/tech-stack-detector").call(run_input={"urls": ["python.org", "nodejs.org"]})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["url"], row["scanStatus"], row["frameworks"], row["hosting"])
```

### Use it from AI agents (MCP)

The Actor can be exposed as a tool through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp). Connect your client to `https://mcp.apify.com?tools=asunoki/tech-stack-detector` (OAuth sign-in, or an `Authorization: Bearer <token>` header) and ask, for example, "Which CMS, CDN, hosting provider and payment tools does example.com use? Include the evidence and confidence." The structured output and the evidence per detection make the answer easy to verify.

### Pricing

Pay per event, per **successfully scanned** website: a **Basic scan** for an HTTP scan and a **Full scan** for a page rendered in a browser. Blocked, robots-skipped and failed rows are not billed. Platform usage is included in the event price; there is no separate compute bill. Price per successfully scanned website: **Basic scan $0.005**, **Full scan $0.015** (the Pricing tab is authoritative). A small per-run start event applies as well. Set a maximum cost per run to cap spend; the Actor stops when the limit is reached.

### Supported technologies (148)

| Category | Technologies | Examples |
|---|---|---|
| A/B testing | 3 | Optimizely, VWO, LaunchDarkly |
| Advertising | 12 | Google Ads, Criteo, Taboola, Outbrain, … |
| Analytics | 15 | Google Analytics, Mixpanel, Amplitude, Hotjar, PostHog, Matomo, … |
| CDN | 9 | Cloudflare, Fastly, jsDelivr, Bunny CDN, … |
| CMS | 11 | WordPress, Wix, Squarespace, Webflow, Joomla, TYPO3, … |
| Consent management | 3 | OneTrust, Cookiebot, Usercentrics |
| Customer support / chat | 8 | Intercom, Zendesk, Crisp, Tawk.to, Gorgias, … |
| DNS provider | 4 | Cloudflare DNS, Google Cloud DNS, Vercel DNS, DigitalOcean DNS |
| Ecommerce | 2 | Shopify, WooCommerce |
| Email infrastructure | 4 | Google Workspace (Gmail), Microsoft 365 (Exchange Online), Zoho Mail, Fastmail |
| Email service | 4 | SendGrid, Mailgun, Postmark, … |
| Fonts | 4 | Google Fonts, Adobe Fonts, … |
| Hosting | 9 | Vercel, Netlify, WP Engine, Kinsta, Heroku, … |
| JavaScript framework | 10 | Next.js, Nuxt, Gatsby, Angular, Astro, … |
| JavaScript library | 4 | jQuery, Bootstrap, Alpine.js, htmx |
| Maps | 3 | map SDKs and embeds |
| Marketing automation | 7 | HubSpot, Marketo, Klaviyo, Braze, … |
| Payment | 8 | Stripe, PayPal, Klarna, Afterpay, Affirm, … |
| Programming language | 1 | PHP |
| Security | 8 | reCAPTCHA, hCaptcha, Cloudflare Turnstile, … |
| Tag manager | 4 | Google Tag Manager, Tealium iQ, … |
| Video | 4 | Vimeo, Wistia, JW Player, … |
| Web framework | 4 | Express, Django, Ruby on Rails, ASP.NET |
| Web server | 7 | nginx, Apache HTTP Server, LiteSpeed, Caddy, … |

The complete list of all 148 technology names is published at https://asunoki.jp/apps/tech-stack-detector/#supported-technologies.

### How the rules are made

Every rule comes from vendor documentation or from public observation of vendors' own sites (HTTP headers, HTML, script and link URLs, cookie names, DNS, TLS), and stores its technology, category, detection method, pattern, source URL, source type, confidence and last-verified date. Rules whose source could not be re-verified are excluded. The engine does not use, copy or derive from any third-party or commercial technology-fingerprint database. An LLM helped write the rules; the source-first process and mechanical re-verification are the safeguards, and they cannot prove that no influence from training data exists.

### Support

Questions or a wrong detection? Open an issue on the Actor's Issues tab or write to support@asunoki.jp with the URL and the run link.

### Responsible use

The Actor requests publicly served pages the way a browser would, at low rate, does not log in or submit forms, and never stores cookie values. You are responsible for using the results in line with applicable laws, the terms of the sites you analyze and your own data-protection obligations. Technology and company names are trademarks of their respective owners; this Actor is not affiliated with or endorsed by any of them.

# Actor input Schema

## `urls` (type: `array`):

Bulk input: one domain or URL per line, up to 10,000. Plain domains (example.com) and full URLs are accepted; https:// is assumed when missing; duplicates are removed. Each site is fetched once.

## `browserFallback` (type: `boolean`):

OFF by default. When ON, a page that returns only a thin JavaScript shell (little visible text after a plain request) is re-rendered in headless Chromium so runtime-loaded technologies become visible. This makes those pages take roughly 10–30 seconds instead of 2–4 seconds and bills them as a Full scan instead of a Basic scan. Pages that do not need it stay Basic. Blocked pages are never retried in a browser.

## `alwaysUseBrowser` (type: `boolean`):

OFF by default. Renders every reachable page in headless Chromium to catch tags injected after page load (for example analytics loaded through a tag manager). Roughly 10–30 seconds per page, at most 2 pages at a time, and every successfully rendered page is billed as a Full scan. If the browser step fails on a site, its plain-HTTP result is returned, billed as Basic, and `browserError` explains why. Blocked pages are never retried or bypassed.

## `respectRobotsTxt` (type: `boolean`):

ON by default and recommended. Before scanning a site the Actor reads its /robots.txt (once per host) and skips the page if the rules disallow it for this Actor's user agent (TechStackDetector) or for all bots. Skipped pages are reported as `skipped_robots` and are not billed. A missing robots.txt (4xx) allows scanning; a server error (5xx) is treated as disallow, as in RFC 9309. Turn this OFF only for sites you own or have permission to scan; you are responsible for that choice.

## `maxConcurrency` (type: `integer`):

How many websites are scanned in parallel. Requests to the same host are never sent in parallel. Browser rendering is capped at 2 pages at a time regardless of this value.

## `timeoutSecs` (type: `integer`):

Time limit for each website's page request. Sites that do not answer in time are reported as `timeout` and are not billed.

## `includeDns` (type: `boolean`):

Resolve A/AAAA/CNAME, name servers, MX and SPF records. Used to detect the DNS provider, the mailbox provider (from MX) and email services authorized in SPF. An SPF entry only shows that a service may send mail for the domain, so it is reported with low confidence.

## `includeTls` (type: `boolean`):

Read the certificate issuer, expiry and protocol. No page content is involved.

## `includeEvidence` (type: `boolean`):

Return the exact signal (response header, meta tag, script URL, cookie name, DNS record) that led to every detection, with a strength flag (`strong` or `weak`). Turn off for smaller output.

## `minConfidence` (type: `integer`):

Drop detections below this confidence (1–99) from the output. 0 keeps everything. Weak inferences (for example an SPF include or a preconnect hint) never score above 60, so a value of 65–70 returns only detections backed by direct evidence.

## Actor input object example

```json
{
  "urls": [
    "python.org",
    "kubernetes.io",
    "nodejs.org"
  ],
  "browserFallback": false,
  "alwaysUseBrowser": false,
  "respectRobotsTxt": true,
  "maxConcurrency": 10,
  "timeoutSecs": 20,
  "includeDns": true,
  "includeTls": true,
  "includeEvidence": true,
  "minConfidence": 0
}
```

# Actor output Schema

## `results` (type: `string`):

All rows: scanStatus, detected technologies with confidence, evidenceStrength and evidence, plus the flat summary fields (cms, ecommercePlatform, frameworks, analytics, cdn, hosting, ...).

## `overview` (type: `string`):

Compact table view of the same rows.

## `runStatistics` (type: `string`):

Counts of ok / blocked / error / skipped_robots rows, billed events, block reasons and durations for this run (key-value store record STATS).

# 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

```javascript
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": [
        "python.org",
        "kubernetes.io",
        "nodejs.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("asunoki/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

```python
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": [
        "python.org",
        "kubernetes.io",
        "nodejs.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("asunoki/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

```bash
echo '{
  "urls": [
    "python.org",
    "kubernetes.io",
    "nodejs.org"
  ]
}' |
apify call asunoki/tech-stack-detector --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,asunoki/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/nxFsyxDLxKYTvSq0Q/builds/gNCBxdzvQ5IcmYOzO/openapi.json
