# Website Technology Detector: Tech Stack, CMS, Tags (`ucchiii/website-technology-detector`) Actor

Detect the tech stack of websites in bulk (input: list of URLs): CMS, frameworks, analytics, tag managers, ad pixels, CDN, consent tools, payments. 230+ technologies, GTM/GA4/pixel IDs, one flat row per URL. Empty input = free demo. $2 per 1,000 sites; failures free.

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

## Pricing

from $1.40 / 1,000 site analyseds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Technology Detector — tech stack, CMS, analytics and tag IDs in bulk

**Paste a list of websites, get a spreadsheet of what each one is built with.** CMS, framework, hosting/CDN, analytics,
tag managers and ad pixels — one flat row per site, ready for Excel or Google Sheets.

**Try it free:** leave the input empty and press **Start** — you get a demo table in seconds, nothing is charged.

| url | technologyNames | gtmIds |
|---|---|---|
| https://apify.com | Amazon CloudFront, Next.js, Intercom, Google Tag Manager | GTM-MNGXGGB |
| https://www.python.org | Fastly, Font Awesome, jQuery, jQuery UI, Modernizr, Varnish, nginx | |

*(real output from a test run on 2026-10-20)*

- **Who it's for:** agencies, sales teams building prospect lists by technology, market researchers, developers.
- **Bulk:** up to 1,000 URLs per run; one request per site, no proxies or browser needed.
- **Tag IDs included:** GTM, GA4, Google Ads and Meta Pixel IDs found in the page source.
- **Price:** $2 per 1,000 sites analysed (100 sites cost 20 cents). Failed, blocked or error pages are **not charged**.
  Store discounts apply automatically: BRONZE −10%, SILVER −20%, GOLD −30%.

### Use cases

- **Market and competitor research**: which sites in a list run Shopify, WordPress, Webflow, Next.js and so on
- **Prospect lists by technology**: filter a CSV of domains by platform, payment provider or chat tool
- **Tag inventory**: collect the GTM container IDs, GA4 measurement IDs, Ads IDs and pixel IDs that appear in the page source of many sites at once
- **Migration and handover notes**: record what a site currently uses (server, CDN, CMS version when the page states it)

### What you get (one row per URL)

| Column | Content |
|---|---|
| `url`, `finalUrl`, `status` | the address you gave, where it ended after redirects, the HTTP status |
| `technologyNames` | comma-separated list, for example `WordPress, Cloudflare, Google Tag Manager` |
| `categories` | comma-separated categories, for example `CMS, CDN, Tag manager` |
| `gtmIds`, `ga4Ids`, `adsIds`, `metaPixelIds` | public IDs found in the page source |
| `otherTrackingTags` | other tag IDs, as `TikTok Pixel: XXXX, Hotjar: 123456` |
| `technologies` | JSON array: `name`, `category`, `version` (when the page states it) and `evidence` |
| `trackingTags` | JSON array of `{name, id}` |
| `checkedAt`, `error` | time of the request and the error code if the page could not be read |

`evidence` says exactly where each technology was seen, for example `script src contains googletagmanager.com/gtm.js?id=GTM-ABC1234`,
`header server: nginx/1.24.0`, `meta generator: WordPress 6.4.2` or `cookie name _fbp`.

### Example

Input:

```json
{ "urls": ["https://example.com", "shop.example.org", "https://www.python.org"], "includeTracking": true }
```

Output row (shortened, illustrative):

```json
{
  "url": "https://www.example.org", "finalUrl": "https://www.example.org/", "status": 200,
  "technologyNames": "Cloudflare, Google Tag Manager, jQuery",
  "categories": "CDN, JavaScript library, Tag manager",
  "gtmIds": "GTM-XXXXXXX", "ga4Ids": "", "adsIds": "", "metaPixelIds": "", "otherTrackingTags": "",
  "technologies": [{"name": "Google Tag Manager", "category": "Tag manager", "version": null,
                    "evidence": "script src contains googletagmanager.com/gtm.js?id=GTM-XXXXXXX"}],
  "checkedAt": "2026-10-20T09:00:00+00:00", "error": null
}
```

Addresses without `https://` are accepted and get `https://` added.

### What it detects (230+ technologies, rules written for this Actor)

- **CMS, site builders and ecommerce**: WordPress, Shopify, Wix, Squarespace, Webflow, Drupal, Joomla, Ghost, HubSpot CMS, Magento, WooCommerce, BigCommerce, PrestaShop, TYPO3, Framer, static site generators and headless CMS
- **JavaScript and CSS**: React, Next.js, Vue.js, Nuxt, Angular, Svelte, jQuery, Alpine.js, htmx, Bootstrap, Tailwind CSS and more
- **Servers, CDN and hosting**: nginx, Apache, Cloudflare, Fastly, Akamai, Amazon CloudFront, Vercel, Netlify, Google Cloud, Azure and more
- **Analytics and tags**: Google Analytics 4, Universal Analytics, Google Tag Manager (including a loader served from a custom domain), Google Ads, Meta Pixel and Conversions API page markers, TikTok Pixel, LinkedIn Insight Tag, Microsoft Clarity, Hotjar, Segment, Mixpanel, Amplitude, Plausible, Matomo and more
- **Consent tools**: OneTrust, Cookiebot, Didomi, Usercentrics, CookieYes, Iubenda and more
- **Chat, support, payments, fonts, maps, video**: Intercom, Zendesk, Drift, HubSpot, Stripe, PayPal, Klarna, Google Fonts, Adobe Fonts, Google Maps and more

Set `includeTracking` to `false` to leave analytics, tag managers, ad pixels and session-replay tools (and the ID columns) out of the result.

### How it works

- **One request per URL** (redirects followed, up to 5). It reads the response headers, the **names** of cookies the server sets (never their values), the HTML (first 2 MB) and the `src` of script tags. **External JavaScript files are not downloaded.**
- Because only the first page is read, technologies that a site loads after the page is rendered in a browser are not seen. Results reflect what a plain HTTP client receives.
- Polite by design: 8 sites in parallel, at most 2 connections per host, 20 second timeout, an honest User-Agent.
- Internal and private addresses (localhost, private ranges, `169.254.169.254`) are never contacted, including redirect targets; the row gets `blocked_private_address`.
- Detection only: the output lists what is present and where it was seen.

### Price

| Event | Price |
|---|---|
| `site` (one URL fetched and analysed, HTTP status below 400) | $0.002 |

**Not charged:** timeouts, DNS failures, redirect loops, HTTP 4xx/5xx pages, blocked and invalid URLs, and the empty-input demo. A row is charged only after it has been written to the dataset. If you set a maximum cost per run, the run stops when the limit is reached.

### Notes

Only request addresses you are allowed to access. Some sites block automated requests; those rows show the HTTP status or error. Versions are reported only when the page, header or script address states them.

### More tools from the same developer

- [Website Screenshot API](https://apify.com/ucchiii/website-screenshot) — screenshots and PDFs of web pages: full page, mobile, element, no cookie banners
- [Bulk URL Status Checker](https://apify.com/ucchiii/url-status-checker) — bulk HTTP status and redirect-chain checker for URL lists
- [Domain WHOIS & DNS Lookup](https://apify.com/ucchiii/domain-whois) — bulk WHOIS (RDAP) and DNS lookup: registrar, expiry, days left, A/MX/NS, no personal data
- [Sitemap URL Extractor](https://apify.com/ucchiii/sitemap-urls) — list every URL of a website from its sitemaps
- [Dataset Merge & Dedup](https://apify.com/ucchiii/dataset-dedup-merge) — merge Apify datasets and remove duplicates by the fields you choose

# Actor input Schema

## `urls` (type: `array`):

Public website addresses to analyse, up to 1,000 per run, for example https://example.com. One page is requested per URL (redirects are followed, up to 5). Leave empty for a free demo on example.com and python.org (not charged). Internal and private addresses are refused.

## `includeTracking` (type: `boolean`):

true (default): list analytics, tag managers, ad pixels and session-replay tools, and fill the ID columns (gtmIds, ga4Ids, adsIds, metaPixelIds, otherTrackingTags). false: leave those out and list only the other technologies.

## Actor input object example

```json
{
  "urls": [
    "https://example.com",
    "https://www.python.org"
  ],
  "includeTracking": true
}
```

# Actor output Schema

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

One flat row per URL: url, finalUrl, status, technologyNames, categories, gtmIds, ga4Ids, adsIds, metaPixelIds, otherTrackingTags (comma-separated text), plus technologies (name, category, version, evidence), trackingTags, checkedAt and error.

# 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 = {
    "urls": [
        "https://example.com",
        "https://www.python.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ucchiii/website-technology-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 = { "urls": [
        "https://example.com",
        "https://www.python.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("ucchiii/website-technology-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 '{
  "urls": [
    "https://example.com",
    "https://www.python.org"
  ]
}' |
apify call ucchiii/website-technology-detector --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ucchiii/website-technology-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/2IQ2xrlIzbu6dY6aV/builds/RLQnBh9hNLxFOBc5o/openapi.json
