# Tech Stack Detector: CMS, Analytics, CDN (`kelp_forest_labs/tech-stack-detector`) Actor

See the CMS, ecommerce platform, JS frameworks, analytics, CDN, hosting and backend a site visibly uses, with evidence and confidence for each. 83 original rules. Reads only robots.txt and the homepage; refusals and errors are free.

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

## Pricing

from $5.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

For each domain, see **which CMS, ecommerce platform, JavaScript framework, analytics and tag tools, CDN, hosting,
web server and backend** its public homepage visibly uses, with the evidence behind every answer.

### Use cases

- Qualify sales leads by platform (e.g. stores on a given ecommerce platform).
- Competitor research for agencies and product teams.
- Find sites that still run outdated software versions they publish.
- Enrich a domain list before outreach or analysis.

### What it does

- 83 original rules in 26 categories (CMS, ecommerce, site builders, static site generators, JS frameworks and
  libraries, analytics, tag managers, session replay, A/B testing, CDN, hosting/PaaS, web servers, backend languages
  and frameworks, bot protection, consent, payments, live chat, error monitoring, fonts, maps, video, public JS CDNs).
- Matches response headers, cookie names, script/stylesheet URLs, `<meta name="generator">`, HTML attributes and
  inline-script references. Versions are reported when the site publishes them (e.g. `generator`, `Server`).
- Every detection carries a **confidence** (`high` = a strong signal or two independent signals, `medium` = one weak
  signal or implied) and up to three **evidence** strings. Implied technologies (WooCommerce ⇒ WordPress ⇒ PHP) are
  marked with `impliedBy`.
- Results also grouped `byCategory` for quick filtering and CSV export.

### Polite and honest

- Two requests per domain: `/robots.txt`, then the homepage, only if robots.txt allows our identified user agent
  (`KelpForestLabs-TechStack/1.0`, product tokens `kelpforestlabs-techstack` and `kelpforestlabs`) on `/`.
  robots.txt 5xx or unreachable is treated as "disallow", as RFC 9309 says.
- No JavaScript is executed, no other pages are crawled, no login walls are touched, no personal data is collected.
- Redirects are followed manually (max 5) and every hop is checked; private, internal and cloud-metadata addresses
  are never contacted.

### Original rule set

The rules were written from scratch from vendors' own documentation and our own observation of public sites. No
third-party or licensed signature set was used. Each rule records its source (a
vendor documentation page or a dated observation) in the rule set itself. Weak signals, such as a generic Rails-style
`_session` cookie or a `Server: Cowboy` header (Heroku, but also other hosts), give only `medium` confidence on
their own.

### Pricing (pay per event)

| Event | Price | When |
|---|---|---|
| `domain` | US$0.005 | a homepage was fetched and analysed (also when nothing is detected) |

Free: domains closed to us by robots.txt, homepages answering 4xx/5xx, domains that do not resolve or are
unreachable, and private/reserved addresses. Platform usage is included in the event price.

Each run also has Apify's run-start charge of US$0.00005 per GB of run memory (US$0.00005 at the default 512 MB),
charged when the run starts, even if every domain fails.

### How to use

1. Open the actor in Apify Console and fill in the input form (or paste the JSON example below into the JSON editor).
2. Optional: set a maximum charge for the run under the run options to cap what a run can cost.
3. Click **Start**. Results appear in the **Output** tab as they are produced; export them as JSON, CSV, Excel or HTML.

You can also start runs from the Apify API or CLI, run the actor on a schedule (for example weekly), and send
results to other apps with Apify integrations and webhooks.

### Input example

```json
{"domains": ["example.com", "https://shop.example.org"], "includeEvidence": true}
```

### Output example (offline fixture run, Oct 7, 2026; one row, trimmed)

```json
{"domain": "https://blog.example", "status": "ok", "httpStatus": 200, "technologyCount": 3,
 "byCategory": {"Analytics": ["Plausible Analytics"], "Static site generator": ["Hugo"], "Web server": ["Caddy"]},
 "technologies": [
  {"name": "Plausible Analytics", "category": "Analytics", "version": null, "confidence": "high", "evidence": ["asset https://plausible.io/js/script.js"], "impliedBy": null},
  {"name": "Hugo", "category": "Static site generator", "version": "0.125.4", "confidence": "high", "evidence": ["meta generator: Hugo 0.125.4"], "impliedBy": null},
  {"name": "Caddy", "category": "Web server", "version": null, "confidence": "high", "evidence": ["header server: Caddy"], "impliedBy": null}],
 "robotsTxt": "found", "rulesVersion": "2026.10.08.1"}
```

### FAQ

**How accurate is it?**
It reports only what the homepage shows (headers, cookies, scripts, generator tags), with the evidence for each item. Tools loaded later by JavaScript or used on other pages may be missed; "not detected" never means "not used".

**Where do the rules come from?**
Our own rule set, written from vendors' public documentation and our own observation. No third-party signature lists; the source of each rule is recorded with the rule set.

**What do `high` and `medium` confidence mean?**
`high` is a strong signal (for example a generator tag or a vendor header) or two independent signals. `medium` is one weak signal, such as a generic session cookie name (for example a Rails-style `_session` cookie) or a shared server header (for example `Cowboy`, used by Heroku but also elsewhere), or a technology implied by another one. Treat `medium` as a lead to verify.

**Is a site charged when nothing is detected?**
Yes, if the homepage was fetched and analysed (that answer is still a result). Sites closed by robots.txt, errors and unreachable domains are free.

**Trademarks?**
Technology names are used only to identify the technologies detected. This tool is not affiliated with or endorsed by their owners.

### Limits: what this actor does not do

- It only sees what the homepage exposes: technologies loaded later by JavaScript, used on other pages or hidden
  behind a proxy are not detected. "Not detected" never means "not used".
- It is not a security scanner. Weak HTML signals (for example a `/wp-content/` path) can also match a page that
  only mentions them in text; such detections are marked `medium`.
- robots.txt and the homepage must each load within 30 seconds; a slower site gets a free error row.

### Changelog

- 1.0 (October 2026): first public version. Rules version 2026.10.08.1 (83 rules).
- Planned, not yet detected: Magento / Adobe Commerce, PrestaShop, Mailchimp, Microsoft IIS and Java Servlet. Their
  rules are held back until we confirm them on live public sites.

# Actor input Schema

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

e.g. example.com or https://example.com. Only robots.txt and the homepage of each domain are requested.

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

Add the matched header, cookie, asset URL or HTML snippet behind each detection.

## Actor input object example

```json
{
  "domains": [
    "apify.com"
  ],
  "includeEvidence": true
}
```

# Actor output Schema

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

One row per domain with the detected technologies, evidence and confidence, or a free error row.

# 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": [
        "apify.com"
    ]
};

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

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

```

## MCP server setup

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