# Website Tech Stack Detector: CMS, Ecommerce, Email, CDN (`bisketapis/website-tech-stack-detector`) Actor

Bulk technology detection for any list of domains from one homepage request each. Returns CMS, ecommerce platform, analytics, ad pixels, payment providers, CDN, hosting, email provider and mail senders (from DNS), social links and a contact email.

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

## Pricing

$1.00 / 1,000 domain analyseds

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 Tech Stack Detector: CMS, Ecommerce, Email, CDN

Give it a list of domains. For each one it makes a single homepage request plus a few DNS lookups and returns the website's technology stack: CMS, ecommerce platform, analytics, ad pixels, payment providers, CDN, hosting, **email provider and mail senders read from DNS**, social profile links and a published contact mailbox. Domains that cannot be reached are returned with the reason and are **not charged**.

It is a BuiltWith / Wappalyzer style detector built for sales prospecting and competitive research: one flat row per domain that drops straight into a CRM or spreadsheet.

Pairs with `shopify-technographics-leads` (finds Shopify stores) when you want to profile a list of stores you already have.

### What you get per domain

- **Standard fingerprints:** 7,600+ technologies in 100+ categories, matched on response headers, cookies, HTML, script URLs, inline scripts, meta tags and URL, with version numbers and a confidence score. Rules `implies`, `excludes` and `requires` are applied.
- **Flat fields for filtering:** `cms`, `ecommercePlatform`, `analytics[]`, `adPixels[]`, `paymentProviders[]`, `cdn`, `hosting`.
- **Email stack from DNS:** `emailProvider` (Google Workspace, Microsoft 365, Zoho Mail, Proofpoint, Mimecast...) from MX records, `emailSenders[]` (SendGrid, Mailchimp, Klaviyo, HubSpot...) from SPF includes, plus raw `mxRecords`, `spfIncludes`, `nameservers`. TXT verification records also reveal SaaS tools the company uses (DocuSign, Atlassian, OpenAI...), marked `detectedVia: ["dns"]`.
- **Ecommerce details:** Shopify theme name and version, `myshopify.com` domain and shop name, city, country and currency (from `/meta.json`), BigCommerce store hash, WooCommerce version.
- **Page facts:** HTTP status, final URL, title, language, social links (Facebook, Instagram, X, LinkedIn, YouTube, TikTok, Pinterest, GitHub) and a business contact mailbox (`info@`, `support@`, `sales@` style addresses only, never a named person).

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `domains` | array | 4 sample domains | Domains or full URLs. Path is ignored. Duplicates removed. |
| `includeDns` | boolean | `true` | MX, TXT, NS, SOA over DNS-over-HTTPS. |
| `categoriesFilter` | array | none | Only list technologies whose category contains a word, e.g. `ecommerce`, `analytics`, `payment`, `cms`, `advertising`. |
| `minConfidence` | integer | `0` | Use 50 to drop weak single-signal matches. |
| `maxDomains` | integer | `1000` | Safety cap. |
| `maxConcurrency` | integer | `15` | 1 to 20 domains in parallel. |
| `proxyConfiguration` | object | Apify datacenter | Used for one retry only when a site answers 403, 429 or 503. |

```json
{ "domains": ["shopify.com", "allbirds.com", "wordpress.org", "discount-pantry.com"], "includeDns": true }
```

### Output example (real run, trimmed)

```json
{
  "domain": "allbirds.com",
  "finalUrl": "https://www.allbirds.com/",
  "status": 200,
  "reachable": true,
  "title": "Allbirds: Comfortable, Sustainable Shoes & Apparel",
  "language": "en-US",
  "technologies": [
    { "name": "Shopify", "categories": ["Ecommerce"], "version": null, "confidence": 100, "detectedVia": ["meta", "scriptSrc"] },
    { "name": "Cloudflare", "categories": ["CDN"], "version": null, "confidence": 100, "detectedVia": ["headers"] },
    { "name": "Google Tag Manager", "categories": ["Tag managers"], "version": null, "confidence": 100, "detectedVia": ["html"] }
  ],
  "cms": null,
  "ecommercePlatform": "Shopify",
  "cdn": "Cloudflare",
  "emailProvider": "Microsoft 365",
  "emailSenders": [],
  "spfIncludes": ["allbirds_com._es.easydmarc.com", "spf.protection.outlook.com"],
  "nameservers": ["ns1.markmonitor.com", "ns2.markmonitor.com"],
  "ecommerceDetails": { "shopifyTheme": "allbirds-theme", "shopifyThemeVersion": "1.231.12", "myshopifyDomain": "weareallbirds.myshopify.com", "name": "Allbirds", "city": "Beverly Hills", "country": "US", "currency": "USD" },
  "socialLinks": { "instagram": "https://instagram.com/allbirds", "facebook": "https://facebook.com/weareallbirds", "tiktok": "https://tiktok.com/@weareallbirds" },
  "contactEmail": "help@allbirds.com",
  "scrapedAt": "2026-10-31T01:50:01+00:00"
}
```

### Pricing

Pay per event, no start fee.

| Event | Price |
|---|---|
| Domain analysed (reachable, HTTP status below 400) | $0.001 |
| Unreachable, blocked (403/429), DNS failure | free |

Cost per 1,000 domains: **$1.00** plus normal platform compute (a 30 domain run takes about 30 seconds).

### Use cases

- Build a lead list of every Shopify or WooCommerce store in a domain list, with theme, country and currency.
- Find companies on Google Workspace vs Microsoft 365, or using SendGrid / Mailchimp / Klaviyo, for outbound targeting.
- Competitor monitoring: schedule runs and diff the technology list.
- Agencies: audit a client's stack, CDN, analytics and ad pixels before a pitch.

### FAQ

**How many requests per domain?** One homepage GET, four DNS-over-HTTPS lookups, and one `/meta.json` GET only for Shopify sites.
**Does it run a browser?** No. Technologies that only reveal themselves after JavaScript runs (rules based on JS globals or the rendered DOM) are not detected. Server headers, HTML, script URLs, cookies, meta tags and DNS cover the large majority of CMS, ecommerce, CDN, analytics and hosting detection.
**Why is a site unreachable?** Some sites answer 403 to automated traffic even through a datacenter proxy. They come back with `status: 403`, still show DNS-derived fields, and are free. The actor does not use residential proxies or evade bot protection.
**Is the contact email personal data?** Only role mailboxes already published on the homepage are returned (info, contact, support, sales and similar). Named individuals are skipped.
**Where do the fingerprints come from?** The open-source community Wappalyzer fingerprint set (`enthec/webappanalyzer`, GPL-3.0). The attribution and licence file ship with the actor. The detection engine is original code.

### Limits

- Homepage only; subpages and logged-in areas are not analysed.
- Versions are only reported when the page exposes them.
- Confidence is the sum of matching signals, capped at 100.
- DNS-based entries show that a domain was verified with a service, which usually but not always means active use.

# Actor input Schema

## `domains` (type: `array`):

One per line. A bare domain (allbirds.com) or any URL; the path is ignored and the homepage is analysed.

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

Reads MX, TXT, NS and SOA records over DNS-over-HTTPS. Adds email provider, mail senders (SPF) and SaaS tools the company has verified a domain with.

## `categoriesFilter` (type: `array`):

Optional. Keeps only technologies whose category contains one of these words, e.g. ecommerce, analytics, payment, cms, advertising. The flat fields (cms, cdn, emailProvider...) are always filled.

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

0 reports everything; 50 drops weak single-signal matches.

## `maxDomains` (type: `integer`):

Safety cap on how many domains from the list are processed.

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

Each domain is a different host, so 10-20 is polite.

## `proxyConfiguration` (type: `object`):

Requests go direct first. The datacenter proxy is used for one retry when a site answers 403/429/503 or refuses the connection.

## Actor input object example

```json
{
  "domains": [
    "shopify.com",
    "allbirds.com",
    "wordpress.org",
    "discount-pantry.com"
  ],
  "includeDns": true,
  "minConfidence": 0,
  "maxDomains": 1000,
  "maxConcurrency": 15,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `runSummary` (type: `string`):

Per-domain status and http counts.

# 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 = {
    "domains": [
        "shopify.com",
        "allbirds.com",
        "wordpress.org",
        "discount-pantry.com"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("bisketapis/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 = {
    "domains": [
        "shopify.com",
        "allbirds.com",
        "wordpress.org",
        "discount-pantry.com",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("bisketapis/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 '{
  "domains": [
    "shopify.com",
    "allbirds.com",
    "wordpress.org",
    "discount-pantry.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call bisketapis/website-tech-stack-detector --silent --output-dataset

```

## MCP server setup

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