# Website Tech Stack Detector: CMS, Email & SaaS (`openfeeds/website-tech-stack-detector`) Actor

Detect the tech stack of any list of domains: CMS, ecommerce, analytics, CDN, hosting, email provider and SaaS tools from DNS. 6,500+ fingerprints, evidence per match, no browser.

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

## Pricing

from $0.90 / 1,000 domain analysed (html + dns)s

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

### What does Website Tech Stack Detector do?

**Website Tech Stack Detector** is a bulk **tech stack lookup API** for any list of company domains. For every domain it returns the **CMS, ecommerce platform, analytics, tag managers, marketing automation, CRM, live chat, payments, JavaScript frameworks, CDN, hosting, web server and cookie consent**, plus the **email provider, email security gateway, sending services and SaaS from DNS** (helpdesk, status page, DNS provider, DMARC policy and vendor). Every technology comes with a **confidence score and the evidence that matched**, so your technographics are explainable.

It needs no browser and no login: one polite homepage request per domain (after robots.txt and text-and-data-mining checks) plus a handful of public DNS lookups.

### Why use Website Tech Stack Detector?

- **6,500+ fingerprints checked without a browser**, plus our own DNS maps for MX, SPF, domain-verification TXT records (178 prefixes) and subdomain CNAMEs: email provider, email sending services, helpdesk, status page and DMARC vendor.
- **Evidence and confidence for every technology**, e.g. `meta generator: WordPress 7.2` or `SPF include mailgun.org`.
- **CRM-ready flat columns** (`cms`, `ecommerce`, `emailProvider`, `saasFromDns` …) next to the full `technologies` list.
- **Partial results even when a site blocks bots**: DNS and response headers still tell you a lot, at a lower price.
- **Free when nothing is found**: invalid entries, repeated entries and every domain where nothing was detected cost nothing. An unreachable domain is free unless public DNS still reveals a technology; then it counts as a cheaper partial result.
- **Thousands of domains per run**, with polite per-site pacing.
- **Agent-friendly**: one row per non-empty input entry, the same terms in every field, a `status` and a `billedEvent` column.
- Runs on Apify: scheduling, API, webhooks and integrations (Make, Zapier, Google Sheets, Clay-style enrichment pipelines).

**Use cases:** lead qualification ("all Shopify stores using Klaviyo", "companies on Microsoft 365 with HubSpot"), agency prospecting by CMS or email provider, competitive intelligence and adoption counts, CRM enrichment, and AI agents that need to know "what does acme.com run?".

### What data can you get?

| Field | Example | What it is |
|---|---|---|
| `domain` | `apify.com` | Registrable domain used for DNS |
| `status` | `ok` | What happened (see the table below) |
| `cms` | `WordPress` | Content management system or site builder |
| `ecommerce` | `Shopify` | Ecommerce platform |
| `analytics` | `["Google Analytics"]` | Analytics tools on the homepage |
| `marketingAutomation` | `["HubSpot"]` | Marketing automation (HTML or DNS) |
| `cdn` / `hosting` | `Amazon CloudFront` / `Amazon Web Services` | CDN and hosting hint |
| `emailProvider` | `Google Workspace` | Email provider (mailbox provider from MX, or SPF behind a gateway) |
| `emailSecurityGateway` | `Proofpoint` | Inbound email security gateway |
| `emailSendingServices` | `["Mailgun", "Amazon SES"]` | Services allowed to send email (SPF) |
| `saasFromDns` | `["OpenAI", "Zapier"]` | SaaS from DNS: SPF includes, verification TXT records, subdomain CNAMEs |
| `helpdesk` / `statusPage` | `Zendesk` / `Atlassian Statuspage` | Vendors behind `help.` / `status.` |
| `dmarcPolicy` / `dmarcVendor` | `reject` / `dmarcian` | DMARC policy and reporting vendor |
| `dnsProvider` | `Amazon Route 53` | Authoritative DNS provider |
| `technologies` | `[{name, categories, version, confidence, detectedVia, evidence, website}]` | Everything detected |
| `billedEvent` | `domain-analyzed` | What this row cost (`null` = free) |

**Status values**

| Status | Meaning | Contains |
|---|---|---|
| `ok` | Homepage fetched and analysed | HTML, headers and DNS |
| `blocked` | Bot protection: a 401/403, or a challenge or block page of a bot-protection vendor (also when it comes with a 2xx, 405, 429 or 503 status) | Headers and DNS |
| `robotsDisallowed` | robots.txt disallows us or answered with a server error (5xx) | DNS only |
| `tdmReserved` | The site reserved text and data mining | DNS (plus headers if the reservation came in the response) |
| `denylisted` | A platform we never request (see FAQ) | DNS only |
| `dnsOnly` | You turned the homepage check off | DNS only |
| `httpError` | 404, 410 or another 4xx, or a 429/5xx without challenge markers (after retries) | Headers and DNS |
| `unreachable` | DNS, TLS, connection, timeout or redirect failure on robots.txt or the homepage (`errorCode` says which) | DNS only |
| `invalidInput` | Not a public domain or URL | Nothing (free) |

### How to find the tech stack of a website list

1. Paste your domains or URLs into **Domains or URLs**, one per line (`acme.com`, `https://www.acme.com/shop`).
2. Choose what to check: homepage HTML and headers, public DNS, or both (DNS-only is a fast, cheap email-provider check).
3. Click **Start**. Rows appear as domains finish; the run summary is stored as `SUMMARY`.
4. Export the dataset as CSV, JSON, Excel or HTML, or use the **Technologies** view for one row per technology.

### How much does a tech stack check cost?

Pay per domain, not per technology row:

| Event | Free plan | Bronze | Silver | Gold and up |
|---|---|---|---|---|
| **Domain analysed** (HTML + DNS, ≥1 technology) | $1.50 / 1,000 | $1.30 / 1,000 | $1.10 / 1,000 | $0.90 / 1,000 |
| **Partial result** (DNS/headers only, ≥1 technology) | $0.60 / 1,000 | $0.50 / 1,000 | $0.40 / 1,000 | $0.30 / 1,000 |
| Run start | $0.00005 per run (per GB of memory) | same | same | same |

- **Free rows:** invalid input, repeated entries (they get a free copy of the first row) and any domain where nothing billable was detected.
- **Partial results:** a domain that is `blocked`, `robotsDisallowed`, `tdmReserved`, `denylisted`, `httpError` or `unreachable`, or checked in DNS-only mode, is charged as a partial result only if DNS or headers still revealed at least one technology. An `ok` row without analysed HTML is also a partial result: the page was not HTML or was empty (note `nonHtmlContent`), its HTML could not be analysed in time (note `matchTimeout`), or your spending limit could still pay for a partial result but not for an analysed domain (note `spendingLimitPartial`).
- **Worked example:** if 8,000 of 10,000 domains are analysed and 1,000 are partial results, the run costs 8,000 × $0.0015 + 1,000 × $0.0006 = **$12.60** on the Free plan; the other 1,000 rows are free.
- Apify's **$5 monthly free credit covers about 3,300 analysed domains**.
- Technologies of the bot-protection vendor that blocked us (e.g. Cloudflare on a Cloudflare challenge) never make a row billable.
- **Spending limit:** the run never charges more than your maximum charge per run. When the remaining limit cannot pay for the next domain, the run stops with the status message "Spending limit reached". If the limit is below the price of one analysed domain but covers partial results, homepages are checked with headers and DNS only (note `spendingLimitPartial`) and charged as partial results.

### Input

See the **Input** tab for all options. Example (this is the prefilled input):

```json
{
    "domains": ["apify.com", "wordpress.org", "example.com"],
    "fetchHomepage": true,
    "includeDns": true,
    "minConfidence": 50,
    "includeEvidence": true,
    "maxConcurrency": 20,
    "requestTimeoutSecs": 15
}
```

- **Domain or URL:** `acme.com` checks the homepage; `https://www.acme.com/shop` checks exactly that page. Query strings are used for the request but never stored. User names, passwords and e-mail addresses in an entry are removed from the `input` column (such entries are invalid anyway).
- **DNS-only mode:** set `fetchHomepage` to `false` for email provider, sending services, SaaS from DNS and DNS provider without any request to the site (charged as a partial result).
- **minConfidence:** 50 hides weak hints, such as a service only listed in a Content-Security-Policy header; 0 shows everything.

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. A real row for `apify.com` (from a run on 2026-10-13, trimmed):

```json
{
    "inputIndex": 0,
    "input": "apify.com",
    "domain": "apify.com",
    "host": "apify.com",
    "status": "ok",
    "httpStatus": 200,
    "finalUrl": "https://apify.com/",
    "technologyCount": 20,
    "marketingAutomation": ["HubSpot"],
    "jsFrameworks": ["React", "styled-components"],
    "cdn": "Amazon CloudFront",
    "hosting": "Amazon Web Services",
    "emailProvider": "Google Workspace",
    "emailSendingServices": ["Amazon SES", "HubSpot", "Mailgun"],
    "dnsProvider": "Amazon Route 53",
    "saasFromDns": ["Atlassian Statuspage", "Ghost", "Amazon SES", "HubSpot", "Mailgun", "Google Search Console", "Mixpanel", "OpenAI", "Zapier"],
    "statusPage": "Atlassian Statuspage",
    "dmarcPolicy": "reject",
    "dmarcVendor": null,
    "hasMx": true,
    "mxDomains": ["google.com", "googlemail.com"],
    "spfIncludes": ["google.com", "mailgun.org", "amazonses.com", "hubspotemail.net"],
    "technologies": [
        {
            "name": "Amazon CloudFront",
            "categories": ["CDN"],
            "version": null,
            "confidence": 100,
            "detectedVia": ["headers"],
            "evidence": ["header via: 1.1 …cloudfront.net (CloudFront)", "header x-amz-cf-id"],
            "website": "https://aws.amazon.com/cloudfront/"
        },
        {
            "name": "Google Workspace",
            "categories": ["Webmail", "Email"],
            "version": null,
            "confidence": 100,
            "detectedVia": ["dns"],
            "evidence": ["MX aspmx.l.google.com", "MX googlemail.com", "SPF include google.com"],
            "website": "https://workspace.google.com/"
        },
        {
            "name": "Atlassian Statuspage",
            "categories": ["Issue trackers", "PaaS"],
            "version": null,
            "confidence": 100,
            "detectedVia": ["dns"],
            "evidence": ["CNAME status → stspg-customer.com"],
            "website": "https://www.atlassian.com/software/statuspage"
        },
        {
            "name": "OpenAI",
            "categories": ["Artificial Intelligence"],
            "version": null,
            "confidence": 70,
            "detectedVia": ["dns"],
            "evidence": ["TXT openai-domain-verification="],
            "website": "https://openai.com"
        }
    ],
    "notes": [],
    "billedEvent": "domain-analyzed",
    "checkedAt": "2026-10-13T01:01:03.624Z"
}
```

In the same run `wordpress.org` returned `cms: "WordPress"` (version 7.2 from the generator meta tag), Nginx, Google Tag Manager and Help Scout (SPF), and `example.com` returned Cloudflare, Cloudflare DNS and HTTP/3. The **Technologies** view unwinds `technologies` into one row per technology for adoption counts; the **Email & DNS** view shows the email and DNS columns; the **Status & billing** view explains every free or partial row.

### Use with AI agents and the API

Call the Actor from the Apify API, the Apify MCP server or any integration with a small input such as `{"domains": ["acme.com"]}`. Each non-empty input entry produces one row, in completion order (unless a spending limit stops the run early); empty lines are skipped. Join results back to your list with `inputIndex`. A repeated entry (same host and path; the query string is ignored) gets a free copy of the first row with the note `duplicateInput`. `status` tells you how complete the row is, and `billedEvent` tells you what it cost (`domain-analyzed`, `domain-partial` or `null` for free).

### Tips

- Use **4 GB memory** for lists over 2,000 domains: more memory brings more CPU and a faster run, and the per-domain price stays the same.
- `minConfidence: 0` shows weak hints such as Content-Security-Policy-only matches (confidence 40).
- **DNS-only mode** is the cheapest way to map email providers and SaaS from DNS for a large list.
- Results arrive in completion order; sort or join by `inputIndex`.

### FAQ

#### Is it legal to detect a website's tech stack?

The Actor sends one homepage request per domain that you supply and reads public DNS records. It respects robots.txt (RFC 9309) and text-and-data-mining reservations under §44b UrhG: natural-language reservations in robots.txt, `/.well-known/tdmrep.json`, and the `tdm-reservation` header and meta tag. It never logs in, never solves CAPTCHAs, never uses proxies or browser fingerprints to get past bot protection, and identifies itself with an honest user agent (`OpenFeedsTechDetector`). It outputs no personal data: no page titles or text, no e-mail addresses, no verification tokens, DMARC report addresses or SOA contacts. It is meant for company domains; a sole trader's domain can be personal data under the GDPR, so make sure you have a legitimate purpose.

> Our Actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our Actors, when used for ethical purposes by Apify users, are safe. However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

#### Why is a site `blocked` or `robotsDisallowed`?

Some sites block datacenter traffic or disallow crawlers. In a first probe from Apify datacenter IPs, 81% of 68 random mid-tail domains answered with a normal page (most of the rest were Cloudflare challenges). In a test of 300 random mid-tail domains from a home connection (2026-10-13), 67% got a full analysis, 12% were blocked, 4% were disallowed by robots.txt, 1% returned an HTTP error and 15% were unreachable. A blocked, disallowed or unreachable site still gets its DNS results, charged as a partial result only if something was detected. Challenge and block pages are recognised even when they come with a success status, such as an AWS WAF interstitial with 202 or an Akamai "Access Denied" page with 200; their HTML is never analysed.

#### Why is a site `tdmReserved`?

The site reserved its content against text and data mining (§44b UrhG), so its homepage is not analysed. The Actor checks `/.well-known/tdmrep.json`, the `tdm-reservation` header and meta tag, and the comments of robots.txt. A robots.txt comment that mentions text and data mining, TDM or §44b UrhG counts as a reservation. This is conservative by design; paths and user-agent names in robots.txt are ignored.

#### Why did it miss technology X?

Only the homepage (or the exact URL you give) is checked, JavaScript is not executed, and versions appear only when the site exposes them. Please open an issue in the **Issues** tab with an example domain.

#### Which platforms are never requested?

Domains of Google (including YouTube and Blogspot), Amazon, Indeed, Meta (Facebook, Instagram, Threads, WhatsApp, Messenger), LinkedIn, X/Twitter, Reddit and TikTok. They get status `denylisted` with DNS results only. The Actor sends no request to them, not even for robots.txt. If a site or its robots.txt redirects to one of them, the redirect is not followed and the row is `denylisted` with the note `denylistedRedirect`. In that case `finalUrl` shows only the platform's origin.

The exact list:

- **Any country domain:** google, youtube, blogspot, amazon, aboutamazon, indeed, facebook, instagram, whatsapp, linkedin, twitter, reddit and tiktok (e.g. google.de, amazon.co.uk, blogspot.com).
- **Brand top-level domains:** .google, .goog, .youtube, .android, .chrome, .gmail, .gle, .dclk, .amazon, .aws and .kindle.
- **Google domains:** youtu.be, youtube-nocookie.com, youtubekids.com, withyoutube.com, ytimg.com, ggpht.com, googlevideo.com, blogger.com, blogblog.com, gmail.com, googlemail.com, goo.gl, g.co, g.page, g.dev, withgoogle.com, googleblog.com, feedburner.com, googleusercontent.com, googleapis.com, gstatic.com, gvt1.com, gvt2.com, 1e100.net, google-analytics.com, googletagmanager.com, googletagservices.com, googleadservices.com, googlesyndication.com, doubleclick.net, admob.com, android.com and chrome.com.
- **Meta domains:** fb.com, fb.me, fb.watch, fb.gg, fbcdn.net, facebook.net, messenger.com, m.me, instagr.am, ig.me, cdninstagram.com, threads.net, threads.com, whatsapp.net, wa.me, meta.com, oculus.com and workplace.com.
- **Other platform domains:** lnkd.in and licdn.com (LinkedIn); x.com, t.co, twimg.com and twttr.com (X); redd.it, redditmedia.com and redditstatic.com (Reddit); tiktokcdn.com, tiktokcdn-us.com and tiktokv.com (TikTok); amzn.to, amzn.com, amzn.eu, a.co, media-amazon.com, images-amazon.com, ssl-images-amazon.com, amazon-adsystem.com and primevideo.com (Amazon).

Cloud hosting used by other companies' sites (amazonaws.com, appspot.com, web.app, firebaseapp.com) is not on the list, and neither are separately branded subsidiaries such as Twitch or IMDb.

#### Where do the fingerprints come from?

Technology fingerprints come from the open-source webappanalyzer project (github.com/enthec/webappanalyzer, GPL-3.0), used unmodified and pinned to a reviewed version; the version is in `SUMMARY.fingerprintCommit`. Updates ship as new Actor versions and are listed in the changelog. The DNS maps (MX, SPF, verification TXT, NS, subdomain CNAME and DMARC vendors) are our own, built from vendor documentation and a census of public DNS records (TXT records of the top 10,000 domains; MX, NS and DMARC records of the top 4,000).

#### Is this a vulnerability scanner?

No. It provides no CVE or CPE mapping and sends a single ordinary page request.

#### How does it compare with database lookups?

Database-based lookups can include historical and multi-page data. This Actor checks each domain live, at run time, and shows the evidence for every match.

### Limitations

- Homepage only (or the exact URL you give); no crawling and no history.
- No JavaScript execution: 963 of the 7,628 known technologies can only be detected in a browser (884 need JavaScript globals or XHR, 79 CSS, text, TLS issuer or probes), and 2,533 more have their JavaScript rules skipped but stay detectable through other rules. 6,516 technologies have at least one HTTP rule, which is what "6,500+ fingerprints" means.
- DNS verification records show that an account exists or existed, not active use (confidence is capped at 70).
- Block rates depend on the sites; datacenter IPs are blocked more often than home connections.
- At most 2 sites of one platform are checked at a time (e.g. many `*.myshopify.com` or `*.github.io` shops), with at least 250 ms between requests to it, so long lists on one platform run slower.
- Very long values are matched on their first part only: script URLs on the first 2 KB, header, cookie and meta values on the first 4 KB (Content-Security-Policy on the first 32 KB). `data:` script URIs are skipped.

### Changelog

- **1.0 (2026-10-13):** First release. 6,500+ fingerprints, DNS maps for email provider, security gateway, sending services, 178 verification-TXT prefixes, helpdesk, status page, DNS provider and DMARC vendor; robots.txt and TDM compliance; pay-per-event pricing with free rows for invalid input, repeated entries and domains where nothing was detected.

# Actor input Schema

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

Company domains or website URLs to analyse, one per line (e.g. `apify.com` or `https://www.example.com/shop`). Each entry gets one homepage request (or the exact URL you give) plus public DNS lookups. Empty lines are ignored; a repeated entry (same host and path) gets a free copy of the first row; IP addresses and private hosts are rejected as free invalid rows.

## `fetchHomepage` (type: `boolean`):

Analyse the homepage HTML and headers (CMS, analytics, ecommerce, CDN…). Turn off for a fast, cheaper DNS-only check (email provider, SaaS from DNS, DNS provider).

## `includeDns` (type: `boolean`):

Read public DNS records (MX, SPF/TXT, NS, DMARC, and CNAMEs of common subdomains such as help., status. and shop.) to detect the email provider, email security gateway, sending services, SaaS tools from DNS, helpdesk, status page, DMARC vendor and DNS provider.

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

Only return technologies detected with at least this confidence. 50 hides weak hints, such as a service that is only listed in a Content-Security-Policy header. Use 0 to see everything.

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

Add short evidence for every technology, e.g. `meta generator: WordPress 7.2` or `SPF include mailgun.org`. Turn off for smaller output.

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

How many domains are checked in parallel. Requests to the same site are always sequential and polite.

## `requestTimeoutSecs` (type: `integer`):

Timeout for the homepage request. Slow sites that exceed it get a DNS-only result.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "https://www.example.com/shop"
  ],
  "fetchHomepage": true,
  "includeDns": true,
  "minConfidence": 50,
  "includeEvidence": true,
  "maxConcurrency": 20,
  "requestTimeoutSecs": 15
}
```

# Actor output Schema

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

One row per domain: CMS, ecommerce, analytics, CDN, hosting, email provider, SaaS from DNS and status

## `technologies` (type: `string`):

Long format: one row per detected technology with confidence and evidence

## `summary` (type: `string`):

Counts per status, charged events (domain analysed / partial result) and the top technologies

# 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",
        "wordpress.org",
        "example.com"
    ]
};

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

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

```

## MCP server setup

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