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

Give a list of websites and get one row per site with the CMS, shop platform, analytics, ad tags, CDN, hosting, frameworks and other technologies found, each with the evidence it was found by.

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

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

Paste in a list of websites and get back one row per site with the technologies it runs on: the CMS or shop platform, analytics and ad tags, tag manager, CDN and hosting, web server, frameworks, JavaScript libraries, fonts, payment and chat widgets, cookie consent tools and a few security features.

Every technology comes with the evidence it was found by, so you can see why the Actor thinks a site uses Shopify or HubSpot instead of having to take it on trust.

### What you put in

A list of addresses. Home pages work best, but any public page is fine, and a bare domain such as `example.com` is accepted too.

```json
{
  "startUrls": [
    { "url": "https://wordpress.org/" },
    { "url": "https://www.joomla.org/" },
    { "url": "https://nextjs.org/" }
  ]
}
```

Optional settings:

| Setting | What it does |
|---|---|
| `onlySitesUsing` | Keeps only the sites that use at least one of the technologies or categories you list, for example `["Shopify", "live-chat"]`. Useful when you start from a long list of domains and want only the ones on a given platform. |
| `includeFailed` | On by default. Sites that could not be checked still get a row that says why. Turn it off to keep only successful rows. |
| `maxConcurrency` | How many sites are checked at the same time, from 1 to 4. Default 4. |
| `requestDelayMs` | Minimum gap between two requests to the same site. Only matters when you list several pages of one site. Default 1 second. |
| `timeoutSecs` | How long to wait for a slow site before giving up. Default 20 seconds. |

### What you get

One row per site. The `summaryText` column is the one most people paste into a spreadsheet; `technologies` has the full detail.

```json
{
  "url": "https://wordpress.org/",
  "finalUrl": "https://wordpress.org/",
  "statusCode": 200,
  "technologyCount": 6,
  "technologyNames": "WordPress, Google Tag Manager, Nginx, Google Fonts, HSTS, Jetpack",
  "summaryText": "cms: WordPress 7.2; tag-manager: Google Tag Manager; web-server: Nginx; fonts: Google Fonts; security: HSTS; wordpress-plugin: Jetpack",
  "summary": {
    "cms": "WordPress 7.2",
    "tag-manager": "Google Tag Manager",
    "web-server": "Nginx",
    "fonts": "Google Fonts",
    "security": "HSTS",
    "wordpress-plugin": "Jetpack"
  },
  "technologies": [
    {
      "name": "WordPress",
      "category": "cms",
      "version": "7.2",
      "evidence": ["header", "meta", "html"],
      "signals": ["link: <https://wordpress.org/wp-json/>; rel=\"https://api.w.org/\", <https://wo...", "meta generator: WordPress 7.2-alpha-64252", "html: /wp-content/plugins/", "html: /wp-includes/"]
    },
    {
      "name": "Nginx",
      "category": "web-server",
      "version": null,
      "evidence": ["header"],
      "signals": ["server: nginx"]
    }
  ],
  "error": null,
  "checkedAt": "2026-10-10T08:03:57+00:00"
}
```

(The `technologies` list above is shortened to two entries.)

- `evidence` tells you where each technology was seen: a response `header`, a `meta` tag, a `script` tag, a `cookie` name, or the page `html`. A technology seen in more than one place is a safer bet than one seen in a single class name.
- `signals` shows the actual text that matched, cut to a readable length.
- `version` is filled in only when the site reveals it, for example in a generator tag or a file name.
- `summary` has one key per category, so you can split it into columns.

The categories are: cms, ecommerce, analytics, advertising, tag-manager, cdn, hosting, web-server, caching, web-framework, programming-language, javascript-framework, javascript-library, ui-framework, fonts, payments, live-chat, marketing-automation, cookie-consent, security, monitoring, a-b-testing, search, video, maps, reviews, seo, page-builder and wordpress-plugin. Close to 200 technologies are recognised.

### How it works

- It makes one ordinary request for the page you listed, with no browser. That is why it is fast and cheap, and also why it only sees what the site sends in its first response (see Limits).
- Before that request it reads the site's robots.txt and skips the page if robots.txt disallows it. If robots.txt cannot be reached because of a server error, the page is skipped as well, to be safe. A crawl delay in robots.txt is honoured.
- It follows redirects (for example from `example.com` to `www.example.com`) and checks robots.txt again when a redirect leads to another host.
- It keeps only the names of cookies, never their values, and does not collect any information about people.

### Price

Free for now. You only pay Apify's usual platform usage. In our test, 251 sites were checked in about two and a half minutes with the default settings; at 256 MB of memory that should come to roughly two cents of platform usage per 1,000 sites. The three-site example above finishes in a few seconds.

### Limits

- Technologies that are added only by JavaScript after the page loads (some chat widgets, tags loaded from inside a tag manager, single-page apps that render everything in the browser) can be missed. A site that loads Google Tag Manager will often have more tags than this Actor can see.
- Large sites with bot protection may answer with HTTP 403 or 429. You still get a row with the status code and whatever the headers revealed, usually the CDN and the protection service.
- Detection is based on fingerprints, so it can be wrong. The `evidence` and `signals` fields are there so you can check.
- Only the page you list is read. Links are not followed.

This Actor is an independent tool. It is not affiliated with any of the companies whose products it recognises, or with the owners of the sites it checks.

# Actor input Schema

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

Home pages or any other public pages, for example https://wordpress.org/. A bare domain such as example.com also works. Only the page you list is read; links on it are not followed.

## `onlySitesUsing` (type: `array`):

Technology names (such as Shopify or HubSpot) or category keys (such as ecommerce or live-chat). A site is kept when it uses at least one of them. Case does not matter. Leave empty to keep every site.

## `includeFailed` (type: `boolean`):

Adds a row with the reason (for example blocked by robots.txt, or no connection) for every site that could not be checked. Ignored when the filter above is used.

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

How many requests run in parallel. Capped at 4.

## `requestDelayMs` (type: `integer`):

Only matters when you list several pages of the same site. A longer crawl delay in the site's robots.txt always wins.

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

Give up on a site that has not answered within this time.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://wordpress.org/"
    },
    {
      "url": "https://www.joomla.org/"
    },
    {
      "url": "https://nextjs.org/"
    }
  ],
  "includeFailed": true,
  "maxConcurrency": 4,
  "requestDelayMs": 1000,
  "timeoutSecs": 20
}
```

# Actor output Schema

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

One row per website: final URL, HTTP status and the technologies found, grouped by category.

# 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": [
        {
            "url": "https://wordpress.org/"
        },
        {
            "url": "https://www.joomla.org/"
        },
        {
            "url": "https://nextjs.org/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("sampon/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": [
        { "url": "https://wordpress.org/" },
        { "url": "https://www.joomla.org/" },
        { "url": "https://nextjs.org/" },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("sampon/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": [
    {
      "url": "https://wordpress.org/"
    },
    {
      "url": "https://www.joomla.org/"
    },
    {
      "url": "https://nextjs.org/"
    }
  ]
}' |
apify call sampon/website-tech-stack-detector --silent --output-dataset

```

## MCP server setup

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