# Website Tech Stack Detector (`titian_fluorite/tech-stack-detector`) Actor

Technology lookup for any list of domains. Detect CMS, ecommerce platform, analytics, frameworks and CDN in bulk. A Wappalyzer and BuiltWith alternative.

- **URL**: https://apify.com/titian\_fluorite/tech-stack-detector.md
- **Developed by:** [Gerald Dobin](https://apify.com/titian_fluorite) (community)
- **Categories:** Developer tools, Lead generation, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$20.00 / 1,000 analysed domains

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Website Tech Stack Detector

Give this Actor a list of domains and it tells you what each website is built with. It fetches every
site once, reads the response headers, cookies, meta tags, script tags and HTML, and matches all of
it against 7,624 technology fingerprints. You get back one row per domain with the CMS, the
ecommerce platform, the JavaScript frameworks and libraries, analytics and tag managers, ad tech,
CDN, hosting and platform providers, the web server, the security headers, and optionally the TLS
certificate issuer and the email provider from the MX records. Ten domains or ten thousand, the
input is the same list.

### Who it is for

**Sales teams qualifying leads.** Upload the domains from your CRM and filter the result by
`ecommercePlatform`. If you sell a Shopify app, you now know which of your 4,000 prospects run
Shopify, which run BigCommerce, and which run something you cannot integrate with at all. The same
row tells you whether they already use a competitor's analytics or tag manager.

**Agencies auditing prospects.** Before a pitch, run the prospect and their five closest
competitors. The output shows the CMS and its version, the ad and analytics stack, whether the site
sends HSTS and a content security policy, and who issues the certificate. That is a technical audit
slide you can build in ten minutes instead of an afternoon.

**Competitive research and migration targeting.** Run a market list once a quarter and count the
platforms to get technology market share over time. Or go the other way and target a migration:
pull every WordPress site in a list of 50,000 domains, or every site still on an old jQuery, and
hand marketing a segment worth emailing.

### What you get

One dataset row per input domain, with stable field names so you can build on them. This is a real
row from a test run, with the `technologies` array cut down to three entries for readability:

```json
{
  "domain": "allbirds.com",
  "inputUrl": "https://allbirds.com/",
  "finalUrl": "https://www.allbirds.com/",
  "httpStatus": 200,
  "redirected": true,
  "technologies": [
    {
      "name": "Shopify",
      "categories": ["Ecommerce", "CMS"],
      "version": null,
      "confidence": 100,
      "website": "https://shopify.com",
      "evidence": [
        "header:powered-by: Shopify",
        "cookie:_shopify_s",
        "cookie:_shopify_y"
      ]
    },
    {
      "name": "Cloudflare",
      "categories": ["CDN"],
      "version": null,
      "confidence": 100,
      "website": "https://www.cloudflare.com",
      "evidence": ["header:cf-cache-status: DYNAMIC", "header:cf-ray: a37949514d4ab35f-SEA", "header:server: cloudflare"]
    },
    {
      "name": "Google Tag Manager",
      "categories": ["Tag managers"],
      "version": null,
      "confidence": 100,
      "website": "https://www.google.com/tagmanager",
      "evidence": ["html: <!-- Google Tag Manager -->"]
    }
  ],
  "cms": "Shopify",
  "ecommercePlatform": "Shopify",
  "frameworks": [],
  "javascriptLibraries": ["Swiper"],
  "analytics": [],
  "tagManagers": ["Google Tag Manager"],
  "adTech": [],
  "cdn": ["Cloudflare"],
  "hosting": [],
  "paas": [],
  "emailProvider": ["Microsoft 365"],
  "serverHeader": "cloudflare",
  "poweredBy": null,
  "securityHeaders": { "hsts": true, "csp": true, "xFrameOptions": true },
  "sslIssuer": "Let's Encrypt",
  "sslExpiry": "2026-11-09T00:48:32.000Z",
  "tlsError": null,
  "ipAddress": "23.227.38.32",
  "dnsProvider": "MarkMonitor DNS",
  "technologyCount": 10,
  "blocked": false,
  "error": null,
  "detectedAt": "2026-09-07T22:53:03.919Z"
}
```

Every technology carries the `evidence` that produced it, so you can check any result yourself
instead of trusting a score. Evidence names cookies and credential style headers without their
values, so nothing sensitive from a target site ends up in your dataset. Confidence runs from 0 to
100 and is summed across the signals that matched. Version numbers appear when the site exposes
them, for example `WordPress 6.9.7` from the generator meta tag or `jQuery 3.5.1` from the script
URL.

Failed domains still produce a row. If a site does not resolve, times out, refuses the request or
answers with a bot challenge page instead of its content, you get the same fields with `error` set,
`blocked` telling you whether the site turned the request away, and `technologies` empty. Your input
list and your output list line up row for row.

### How to use it

Input fields:

- **Domains or URLs** (required). One entry per line. Bare domains such as `allbirds.com` or full
  URLs such as `https://allbirds.com/collections/mens`. Duplicates are removed.
- **Parallel requests** (default 10). How many sites to fetch at once. Raise it for large lists,
  lower it if you are hitting rate limited hosts.
- **Timeout per site** (default 30 seconds). Slow sites may need 45 or 60.
- **Follow redirects** (default on). Follows the bare domain to www, and HTTP to HTTPS.
- **Read the TLS certificate** (default off). Adds `sslIssuer`, `sslExpiry` and `tlsError`. The
  certificate is read without verification, so a site with an expired or self signed certificate is
  still analysed and `tlsError` says what is wrong with the chain.
- **Look up DNS records** (default off). Adds `emailProvider` from MX records and `dnsProvider`
  from the name servers.
- **Minimum confidence** (default 50). Drops weak matches. Set it to 0 to see everything the
  fingerprints touched.

Run it from the API with curl:

```bash
curl -X POST "https://api.apify.com/v2/acts/titian_fluorite~tech-stack-detector/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "domains": ["allbirds.com", "techcrunch.com", "vercel.com"],
    "minConfidence": 50,
    "resolveDns": true
  }'
```

That returns the dataset rows as JSON in the same request. For long lists, start the run with
`POST /v2/acts/titian_fluorite~tech-stack-detector/runs` and read the dataset when it finishes. The
dataset is also available as CSV, Excel, XML and RSS from the same API, so you can load it straight
into a spreadsheet or a CRM import. Apify client libraries exist for JavaScript and Python, and the
Actor works through the Apify MCP server, so an AI agent can call it as a tool and get the
technology stack of a domain back as structured JSON.

### Pricing

You pay per domain analysed. Every row that comes back with a technology list is one charged event,
and nothing else is billed: no monthly subscription, no per-run fee, no charge for compute time.
Domains that fail (DNS failure, timeout, connection refused, or a site that blocks automated
requests) are not charged, so a bad list costs you only for the parts that worked.

### Accuracy and limits

The detector matches against 7,624 technology fingerprints across more than 100 categories, using
the MIT licensed fingerprint dataset published by ProjectDiscovery. On a 25 domain accuracy suite of
well known sites, it found 41 out of 41 expected technologies, including the CMS on every publisher
tested, the shop platform on every store tested, and the framework and CDN on every SaaS site
tested.

What it does not do:

- **No browser.** Each site is fetched as a single HTTP request, which is why it is fast and cheap.
  Fingerprints that need a running page, such as JavaScript variables set at runtime or React
  internals attached to DOM nodes, are skipped. Anything visible in the HTML, headers, cookies,
  meta tags or script URLs is detected. In practice that covers CMS, ecommerce, CDN, hosting,
  analytics, tag managers and most libraries, and misses some single page apps that render
  everything client side.
- **Sites that block bots.** A minority of large sites answer automated requests with 403 or a
  challenge page. Those come back as an error row and are not charged. Retrying rarely helps.
- **One page per domain.** Only the home page is fetched. A technology used solely on a checkout or
  a blog subpath will not appear.
- **Very large pages cost time.** The whole home page is downloaded, and pattern matching reads the
  first 300 KB of it, so a site that serves a multi-megabyte page uses more of your run than a
  normal one does.
- **Convenience fields follow the dataset categories.** A platform that lists itself as both CMS and
  ecommerce, such as Shopify, appears in both `cms` and `ecommercePlatform`.
- **Email and DNS fields** are empty unless you turn on the DNS lookup option, and `sslIssuer` is
  empty unless you turn on the certificate option.

### Support

Open an issue on the Actor page with the domain and what you expected. Fingerprint gaps and wrong
detections are usually fixed within a few days, and the fingerprint dataset is refreshed regularly.
Feature requests for extra output fields are welcome.

# Actor input Schema

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

The websites to analyse. One per line. You can paste bare domains such as example.com or full URLs such as https://example.com/pricing. Each entry produces one result row.

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

How many sites to fetch at the same time. Higher is faster and uses more memory. Lower it if you are analysing sites that rate limit.

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

How long to wait for a site to answer before giving up on it. Slow sites may need 45 or 60 seconds.

## `followRedirects` (type: `boolean`):

Follow redirects to the final page, for example from the bare domain to www or from HTTP to HTTPS. Turn this off if you only want to see the first response.

## `includeCertificate` (type: `boolean`):

Also open a TLS connection to read who issued the HTTPS certificate and when it expires. Adds about a second per domain.

## `resolveDns` (type: `boolean`):

Also look up MX, TXT and NS records to work out the email provider and the DNS host. Adds about a second per domain.

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

Drop technologies detected below this confidence score, from 0 to 100. The default of 50 keeps solid matches and removes weak guesses. Set it to 0 to see everything.

## Actor input object example

```json
{
  "domains": [
    "allbirds.com",
    "techcrunch.com",
    "vercel.com"
  ],
  "maxConcurrency": 10,
  "timeoutSecs": 30,
  "followRedirects": true,
  "includeCertificate": false,
  "resolveDns": false,
  "minConfidence": 50
}
```

# Actor output Schema

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

Every analysed domain as JSON rows: technologies with evidence, cms, ecommercePlatform, frameworks, analytics, cdn, hosting, sslIssuer and more.

## `resultsCsv` (type: `string`):

The same rows as CSV for spreadsheets and CRM imports.

# 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": [
        "allbirds.com",
        "techcrunch.com",
        "vercel.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("titian_fluorite/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": [
        "allbirds.com",
        "techcrunch.com",
        "vercel.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("titian_fluorite/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": [
    "allbirds.com",
    "techcrunch.com",
    "vercel.com"
  ]
}' |
apify call titian_fluorite/tech-stack-detector --silent --output-dataset

```

## MCP server setup

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