# Website Tech Stack Detector: Shopify, CMS, Pixels (`smartmoney-data/tech-stack-detector`) Actor

Website tech stack detector and lightweight BuiltWith / Wappalyzer alternative: detect ecommerce platform, CMS, analytics, ad pixel, CDN and payment signals on any list of public URLs. One page per URL, confidence scores, robots.txt respected.

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

## Pricing

$20.00 / 1,000 page successfully 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

Scan public website URLs and return the tech stack: ecommerce, CMS, analytics, ad-pixel, CDN, and payment signals, each with a confidence score. This website technology detector also works as a Shopify store detector for lead lists and as a Wappalyzer alternative for partner checks. One page per URL you supply.

Use it to:

- Tag a prospect list with likely platform (Shopify, WooCommerce, and others) before outreach.
- See which homepages show a Meta, TikTok, or other ad-pixel signal.
- Check analytics and tag-manager signals on a set of brand sites.
- Compare CDN and payment signals across competitor homepages.
- Drop flat columns into a sheet or CRM (empty cells mean no signal on that page, not a proof of absence).

Detections are signals, not guarantees. Fingerprints are being tightened. Read `confidence` and spot-check important rows.

### Quick start

1. Leave the two sample URLs, or paste your own homepages (bare domains are fine; `https://` is added if missing).
2. Leave **Always render JavaScript** off for the first run. Auto-render is also off in the sample so the run stays on plain HTTP.
3. Click **Start**. You get one row per URL. Filter `ecommerce_platform` or `tech_names` in the dataset.

### Example input

This matches the form prefill. Two public SaaS homepages, HTTP only: 2 successful pages, $0.04.

```json
{
  "urls": ["https://www.shopify.com", "https://stripe.com"],
  "renderJs": false,
  "autoRenderSpa": false,
  "concurrency": 5,
  "timeoutSecs": 20,
  "retries": 2,
  "respectRobotsTxt": true
}
```

Turn `renderJs` on (and raise run memory to at least 1024 MB, concurrency 1-3) when you care about pixels or other scripts that load after the HTML.

### Example output

One row per URL. Column values below are illustrations of the field shape, not a guaranteed read of those sites.

```json
{
  "url": "https://www.shopify.com",
  "final_url": "https://www.shopify.com",
  "status": 200,
  "ecommerce_platform": "Shopify",
  "cms": null,
  "analytics": ["Google Tag Manager", "Google Analytics"],
  "ad_pixels": [],
  "cdn": ["Cloudflare"],
  "payment": [],
  "tech_count": 8,
  "tech_names": ["Shopify", "Cloudflare", "Google Tag Manager"],
  "technologies": [
    {"name": "Shopify", "categories": ["Ecommerce"], "version": null, "confidence": 100},
    {"name": "Cloudflare", "categories": ["CDN", "Security"], "version": null, "confidence": 100},
    {"name": "Google Tag Manager", "categories": ["Tag Manager"], "version": null, "confidence": 90}
  ],
  "rendered": false,
  "spa_fallback": false,
  "scan_time_ms": 600,
  "error": null
}
```

`error` is null on a successful analysis. Otherwise it is a short reason such as `http_error:403`, `http_error:429`, `fetch_error:…`, `robots_disallow`, or `invalid_url:…`. Those rows are not charged.

### Pricing

Pay per event. Apify platform usage is included in the event price. You don't pay for compute units separately.

| Event | When it is charged | Price | Per 1,000 |
|-------|--------------------|-------|-----------|
| `url-detected` | Once per URL whose page was successfully analysed | $0.02 | $20.00 |

Apify also adds a tiny automatic Actor-start fee of $0.00005 per run.

Charged only when the page loaded with a normal status and `error` is null. Not charged: 4xx/5xx (including 403 and 429), timeouts, DNS or connection failures, `robots.txt` skips, browser errors, and invalid URLs. You still get a row. A challenge page served as HTTP 200 can look like a real page; this Actor does not bypass bot protection, CAPTCHAs, or logins.

Worked examples: the prefill (2 pages) = $0.04. 100 successful pages = $2.00. 940 successful pages out of 1,000 = $18.80. You can set a maximum cost per run in Apify Console; finished rows are kept and later URLs are not started.

### Input fields

| Field | Default | Notes |
|-------|---------|-------|
| `urls` | shopify.com, stripe.com | Required. One page per URL |
| `renderJs` | false | Headless Chromium for every URL. Needs more memory |
| `autoRenderSpa` | true (off in the sample) | Re-scan only if HTML looks like an empty app shell |
| `concurrency` | 5 | Parallel URLs. Use 1-3 with the browser |
| `timeoutSecs` | 20 | Per attempt |
| `retries` | 2 | Extra HTTP tries on timeout or connection error |
| `respectRobotsTxt` | true | Disallowed URLs get an error row and are free |
| `proxyUrl` | — | Optional proxy you operate |
| `userAgent` | polite bot UA | Identifies the scan and that it honors robots.txt |
| `maxUrls` | — | Optional cap on how many input URLs run |

### Tips, limits, FAQ

Coverage is a curated fingerprint set, deepest on ecommerce, WordPress/WooCommerce, payments, and marketing tags. A linked script can produce a false signal; use `confidence` and `technologies`. HTTP mode often misses pixels and payment widgets that load in the browser. Only the URL you pass is scanned, not the rest of the site. Blocked datacenter traffic returns little; an error status is free, a 200 challenge page may not be. Rows are saved as each URL finishes, in completion order.

**Is it legal?** It requests only the public URLs you supply, one page each, and respects `robots.txt` by default. It does not log in, submit forms, or crawl. Fingerprints are MIT-licensed and were written for this Actor. Output describes technologies, not people. You are responsible for downstream use (for example outreach) under the laws that apply to you, including GDPR or PDPA, and under each site's terms.

**Do I need https://?** No. `stripe.com` works.

**Why is ecommerce_platform empty?** No matching signal on that page: blocked, JavaScript-only, or outside the fingerprint set. Check `status` and `error`, and try `renderJs` on that URL.

**Am I charged for 403 or 429?** No. Only rows with `error: null` are charged.

**Can it crawl a site?** No. Add inner URLs yourself if you need them.

Integrations: run it via the Apify API, a schedule, Make, Zapier, n8n, or LangChain/MCP through Apify.

# Actor input Schema

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

Website URLs or bare domains, one page per URL (https:// is added if missing). Charged once per page that is successfully analysed. Blocked, error, timed-out, and robots-skipped URLs get a row but are free. The sample is two public SaaS homepages.

## `renderJs` (type: `boolean`):

Render every URL in headless Chromium. Slower and uses more memory: set run memory to at least 1024 MB and lower concurrency. Leave off for the first run.

## `autoRenderSpa` (type: `boolean`):

If the plain HTML looks like an empty JavaScript app shell, re-scan that URL in headless Chromium. The sample leaves this off so the first run stays on HTTP.

## `concurrency` (type: `integer`):

How many URLs to scan in parallel. Keep it modest (default 5). Use 1-3 with browser rendering.

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

Timeout per attempt for each URL, in seconds.

## `retries` (type: `integer`):

Extra HTTP attempts after a timeout or connection error, with backoff. HTTP error statuses are not retried.

## `respectRobotsTxt` (type: `boolean`):

Skip URLs that robots.txt disallows for this bot. Skipped URLs get an error row and are not charged.

## `proxyUrl` (type: `string`):

Optional HTTP(S) proxy of your own, for example http://user:pass@host:8080. Leave empty to connect directly.

## `userAgent` (type: `string`):

User-Agent sent to websites. The default identifies a polite bot that scans one page per URL and respects robots.txt.

## `maxUrls` (type: `integer`):

Optional cap on how many of the input URLs are processed in this run.

## Actor input object example

```json
{
  "urls": [
    "https://www.shopify.com",
    "https://stripe.com"
  ],
  "renderJs": false,
  "autoRenderSpa": true,
  "concurrency": 5,
  "timeoutSecs": 20,
  "retries": 2,
  "respectRobotsTxt": true,
  "userAgent": "TechStackDetectorBot/1.0 (+https://apify.com; polite research; one page per URL; respects robots.txt)"
}
```

# Actor output Schema

## `overview` (type: `string`):

Table of URLs with ecommerce, CMS, analytics, pixels, CDN, and payment detections.

# 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://www.shopify.com",
        "https://stripe.com"
    ],
    "autoRenderSpa": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("smartmoney-data/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 = {
    "urls": [
        "https://www.shopify.com",
        "https://stripe.com",
    ],
    "autoRenderSpa": False,
}

# Run the Actor and wait for it to finish
run = client.actor("smartmoney-data/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 '{
  "urls": [
    "https://www.shopify.com",
    "https://stripe.com"
  ],
  "autoRenderSpa": false
}' |
apify call smartmoney-data/tech-stack-detector --silent --output-dataset

```

## MCP server setup

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