# Website Tech Stack Detector: CMS, Frameworks, Analytics (`pavel.tashev/website-tech-stack-detector`) Actor

Find what technology a website uses: CMS (WordPress, Shopify), frameworks, analytics, ad tech, CDN, hosting and email provider. Bulk tech stack lookup for lead lists, 7,600+ technologies. Never charges for a failed or empty result.

- **URL**: https://apify.com/pavel.tashev/website-tech-stack-detector.md
- **Developed by:** [Pavel Tashev](https://apify.com/pavel.tashev) (community)
- **Categories:** Developer tools, Lead generation, Open source
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 website analyzeds

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

### What does Website Tech Stack Detector do?

**Website Tech Stack Detector shows which technologies any website uses: CMS, ecommerce platform, JavaScript frameworks, analytics and tag managers, CDN, web server, marketing tools and the domain's email provider.** Give it a list of domains and it returns one clean record per website, with each technology's name, categories, version (when visible) and how it was detected.

It uses **7,600+ open-source technology fingerprints** in the Wappalyzer format and checks each website's response headers, cookies, meta tags, script URLs, HTML and DNS records. It needs **no browser and no API key**, so it is fast and cheap to run on thousands of domains. On Apify you also get API access, scheduling, webhooks and integrations (Make, Zapier, n8n, Google Sheets, HubSpot).

### You are never charged for a failed or empty result

Every result says what it is, and only real results cost anything.

| `status` | Meaning | Charged |
|---|---|---|
| `ok` | A real result | Yes |
| `empty` | Worked, but there was nothing to report | No |
| `blocked` | The website refused the request (bot protection, HTTP 403 or 429) | No |
| `failed` | Could not be done — the `error` field says why | No |
| `truncated` / `partial` | Cut short by a limit you set; what was delivered is kept | Only the delivered part |
| `skipped` | Not attempted, for example after the maximum cost per run was reached | No |

If every input fails, the run itself fails with an explanation instead of reporting success with no data.

The Actor also watches the clock: it stops starting new websites two minutes before the run timeout and says in the run summary how many were left. Raise the timeout or split the list if you see that.

### Why use Website Tech Stack Detector?

- **Lead generation and sales prospecting:** find every Shopify store, WordPress site or HubSpot customer in a list of domains, or prospects that use a competitor.
- **Competitor research:** see which frameworks, analytics and marketing tools competitors run.
- **Market research:** measure technology adoption across an industry or a country's top websites.
- **Agencies and developers:** audit client sites before a migration or a pitch.
- **Data enrichment:** add `cms`, `ecommerce` and `emailProviders` columns to your CRM or spreadsheet.
- **AI agents:** a quick "what is this website built with?" tool through the Apify API and MCP server.

### How to detect a website's technology stack

1. Click **Try for free**.
2. Paste domains into **Websites**, one per line (for example `apify.com` or `https://www.example.com`).
3. Optionally pick **Only these categories** (for example CMS and Ecommerce) or turn off **Check DNS records**.
4. Click **Start**. Most websites take 1–3 seconds.
5. Open the **Output** tab. **Overview** shows one row per website; **All technologies** shows one row per technology.

### Input

| Field | Description | Default |
|---|---|---|
| **Websites** | Domains or URLs, one per line. Duplicates and invalid entries are skipped. | – |
| **Check DNS records** | Look up MX, TXT, NS and SOA records to find the email provider, DNS host and SaaS tools that verified the domain | on |
| **Only these categories** | Keep only technologies from the selected categories | all |
| **Websites in parallel** | 1–50 | 10 |
| **Timeout per website** | Seconds to wait for a website before giving up | 20 |
| **Extra pages per website** | Also check this many other pages on the same site (0–5) | 0 |
| **Minimum confidence** | Drop detections below this confidence (0–100) | 0 |
| **Security headers report** | Report which security headers are set and what each gap means | On |

Example input:

```json
{
  "startUrls": ["apify.com", "wordpress.org", "www.allbirds.com"],
  "includeDns": true
}
```

### Output

One item per website. A real example from a run on 15 September 2026 (technology list shortened):

```json
{
  "url": "https://wordpress.org/",
  "finalUrl": "https://wordpress.org/",
  "domain": "wordpress.org",
  "statusCode": 200,
  "technologies": [
    { "name": "Gutenberg", "categories": ["WordPress plugins", "Editors"], "version": "23.9.1", "confidence": 100,
      "website": "https://github.com/WordPress/gutenberg", "detectedBy": ["dom", "scriptSrc"] },
    { "name": "WordPress", "categories": ["CMS", "Blogs"], "version": "7.2", "confidence": 100,
      "website": "https://wordpress.org", "detectedBy": ["dom", "headers", "html", "meta", "scriptSrc"] }
  ],
  "technologyCount": 13,
  "categoriesSummary": { "CMS": ["WordPress"], "Programming languages": ["PHP"], "Web servers": ["Nginx"] },
  "cms": ["WordPress"],
  "ecommerce": [],
  "analytics": [],
  "frameworks": [],
  "server": ["Nginx"],
  "cdn": [],
  "emailProviders": [],
  "dnsServices": [],
  "error": null,
  "scrapedAt": "2026-09-15T11:51:13.335687+00:00"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Output fields

| Field | Meaning |
|---|---|
| `url`, `finalUrl`, `domain`, `statusCode` | The address you entered, where it redirected to, and the HTTP status |
| `technologies` | The website's technology stack: `name`, `categories`, `version`, `confidence` (0–100), `website`, `detectedBy` |
| `securityHeaders` | Security header report: score, present, missing with meanings, version disclosure, notes |
| `hosting` | `ipAddresses`, `nameservers`, `cname` and the `providers` those names identify |
| `pagesRead` | Which page URLs were actually read for this website |
| `technologyCount`, `categoriesSummary` | Number of technologies and the names grouped by category |
| `cms`, `ecommerce`, `analytics`, `frameworks`, `server`, `cdn` | Ready-made columns for the most requested categories |
| `emailProviders` | Email service from the domain's MX records, for example Google Workspace or Microsoft 365 |
| `dnsServices` | Services found **only** in DNS records (domain-verification TXT records, DNS host). They show tools a company has connected its domain to, not the website's code |
| `error` | Why a website could not be analyzed (not charged) |

`detectedBy` lists the evidence: `headers`, `cookies`, `meta`, `scriptSrc`, `scripts`, `html`, `text`, `css`, `url`, `dom`, `dns` or `implied` (for example PHP is implied by WordPress).

### Security headers, in the same run

Every result carries a `securityHeaders` report, read from the response we already fetch — so it costs nothing
extra and turns a lead-generation run into an audit at the same time:

```json
"securityHeaders": {
  "score": 33,
  "present": ["strict-transport-security", "x-content-type-options"],
  "missing": [
    { "header": "content-security-policy", "meaning": "No policy limiting where scripts may be loaded from." },
    { "header": "referrer-policy", "meaning": "Full URLs may leak to other sites in the Referer header." }
  ],
  "disclosure": { "server": "nginx/1.25.3" },
  "notes": ["Headers name the software and version running the site: server: nginx/1.25.3"]
}
```

Every missing header says **what the gap means**, not just its name. Weak settings are called out too — an HSTS
`max-age` under six months, or a CSP that allows `unsafe-inline` — because a header that is present but toothless
would otherwise score as a tick.

### Where the site is hosted

`hosting` names the provider from the site's own DNS records rather than guessing from IP ranges, which go stale
and mislabel anything behind a CDN:

```json
"hosting": {
  "ipAddresses": ["23.227.38.33"],
  "nameservers": ["gold.foundationdns.com", "gold.foundationdns.net"],
  "cname": null,
  "providers": ["Cloudflare"]
}
```

That example is real: Shopify is served by Foundation DNS, Cloudflare's enterprise brand, whose name never
contains "cloudflare" — the SOA record is what gives it away.

### Looking past the homepage

A homepage is a marketing page. Checkout, analytics and help-desk tools usually live somewhere else. Set
**Extra pages per website** and the Actor also reads up to five other pages on the same site, preferring links
it finds on the homepage over guessed paths, and merges what it finds — the strongest evidence wins and a
version found on any page is kept. `pagesRead` lists exactly which pages were used.

**It is still one charge per website**, however many pages were read.

### How much does it cost to detect website technologies?

This Actor uses **pay-per-event pricing**: you pay a small fee per website analyzed. Websites that can't be loaded, time out or refuse access (HTTP 4xx/5xx) are **never charged**. See the **Pricing** tab for the current price per 1,000 websites; platform compute is included. You can set a maximum cost per run and the Actor stops cleanly when it is reached.

### Tips

- **Enter the homepage.** Most technologies are visible there. Enter a specific URL (for example a shop page) to analyze that page instead.
- **Bulk lists:** keep **Websites in parallel** at 10–20 for large lists and raise the timeout for slow sites. The default 512 MB of memory analyzes about 40 websites per minute; 1–2 GB is faster for lists of tens of thousands.
- **Only need the CMS or shop platform?** Select those categories to get smaller results.
- **Turn off DNS checks** if you only care about the website itself and want slightly faster runs.

### Limitations

- **No browser:** technologies that only appear after JavaScript runs in a browser (JavaScript globals, rendered DOM properties) are not evaluated, and complex CSS selectors in fingerprints are skipped. Server-rendered HTML, scripts, headers and cookies cover most CMS, ecommerce, analytics and marketing tools.
- **Blocked websites:** some sites refuse automated requests (HTTP 403 or 429) or answer with a bot-protection challenge. They are recognised as soon as the response arrives, reported as `blocked` with the reason, and are not charged — the Actor does not spend time fingerprinting a challenge page. Sites behind bot protection usually need a browser and residential proxies, which this Actor does not use.
- **Versions** appear only when a website exposes them.
- **DNS services** reflect domain-verification records, which can remain after a company stops using a tool.

### Related tools

Learn more about the same websites and companies:

- [SEO Audit & Metadata Checker](https://apify.com/pavel.tashev/seo-metadata-audit): check titles, meta descriptions, canonicals and other on-page SEO for pages or whole sites.
- [Broken Link Checker](https://apify.com/pavel.tashev/broken-link-checker): crawl a website and find broken links, images and redirect chains.
- [Company Career Page Jobs Scraper](https://apify.com/pavel.tashev/company-jobs-scraper): get all open jobs from company career pages (Greenhouse, Lever, Ashby and more).

### FAQ and support

**Where do the fingerprints come from?** From the open-source [webappanalyzer](https://github.com/enthec/webappanalyzer) project (a maintained continuation of Wappalyzer's technology data, GPL-3.0), bundled at a fixed version and refreshed periodically.

**Does it collect personal data?** No. It reads technical signals only (headers, markup, public DNS records) and does not store page text, emails or phone numbers.

**Is it legal?** It loads one public page per website, like a browser visit, and reads public DNS records. Use the results in line with applicable laws and the websites' terms.

**Missing a technology or seeing a wrong result?** Open an issue in the **Issues** tab with the domain. Custom enrichment pipelines are available on request.

# Actor input Schema

## `startUrls` (type: `array`):

Domains or URLs to analyze, one per line, for example apify.com, https://www.shopify.com or www.example.com/shop. The page you enter (usually the homepage) is loaded once per website.

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

Also look up the domain's MX, TXT, NS and SOA records to find the email provider (for example Google Workspace or Microsoft 365), DNS host and SaaS tools that verified the domain. These are listed separately in emailProviders and dnsServices.

## `includeCategories` (type: `array`):

Keep only technologies from these categories, for example CMS, Ecommerce or Analytics. Leave empty to keep everything.

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

How many websites are loaded at the same time.

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

Give up on a website that doesn't respond within this time. Websites that fail are not charged.

## `extraPages` (type: `integer`):

Also check this many other pages on the same site (blog, pricing, shop, cart). A homepage is a marketing page; checkout, analytics and help-desk tools usually live elsewhere. Links found on the homepage are preferred over guessed paths. Each site is still charged once.

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

Drop detections below this confidence (0-100). Leave at 0 to keep everything, including lower-confidence guesses.

## `includeSecurity` (type: `boolean`):

Report which security headers the site sets, which are missing and what each gap means, plus any headers that disclose software versions. Read from the response we already fetch, so it costs nothing extra.

## Actor input object example

```json
{
  "startUrls": [
    "apify.com",
    "wordpress.org",
    "www.allbirds.com"
  ],
  "includeDns": true,
  "maxConcurrency": 10,
  "timeoutSecs": 20,
  "extraPages": 0,
  "minConfidence": 0,
  "includeSecurity": true
}
```

# 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

```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 = {
    "startUrls": [
        "apify.com",
        "wordpress.org",
        "www.allbirds.com"
    ]
};

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

```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 = { "startUrls": [
        "apify.com",
        "wordpress.org",
        "www.allbirds.com",
    ] }

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

```bash
echo '{
  "startUrls": [
    "apify.com",
    "wordpress.org",
    "www.allbirds.com"
  ]
}' |
apify call pavel.tashev/website-tech-stack-detector --silent --output-dataset

```

## MCP server setup

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