# Tech Stack Detector — Bulk API, JSON & CSV (`apivault_labs/website-tech-detector`) Actor

Check websites for observed technologies, versions and source coverage; undetected tools remain unknown. Bulk export: JSON, CSV, Excel and API. PPE: $1.5/1K website checks; start fee, usage extra.

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

## Pricing

from $1.50 / 1,000 website technology results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Checker — Wappalyzer & BuiltWith Alternative

![Website technology checker](https://api.apify.com/v2/key-value-stores/NTuf4Zn6Iw9PVvSAt/records/website-tech-detector-readme-hero-v1.png)

**Find out what a website is built with.** Check up to 500 public website URLs per run. Discover CMS, ecommerce platforms, analytics, marketing tools, JavaScript frameworks, hosting, CDN and visible security technologies. Export JSON, CSV or Excel for prospect research, CRM enrichment and website comparisons.

### Start with three choices

1. **Websites to check:** paste domains or page URLs, one per line.
2. **What would you like to check?** Discover the technology stack, check specific tools, or compare technologies across pages.
3. **How much should we check?** Choose Fast for a basic check or Extended for broader coverage. Extended can take longer and increase platform usage.

For specific tools, enter names such as Shopify, WordPress or Google Analytics. Optional filters select which websites enter the results. Advanced settings control additional checks, page limits and optional traffic estimates.

```json
{
  "urls": ["wordpress.org"],
  "scan_goal": "check_tools",
  "scan_profile": "fast",
  "target_technologies": ["Shopify", "WordPress"]
}
```

Use `scan_goal: "overview"` for an overview or `"compare_pages"` to compare up to three pages per website. Unknown tool names give an input error. Technology names ignore letter case.

### Read your results

Open **Check report** for findings, unavailable inputs and recommended next steps. **Check answers** provides a compact dataset view. **Check report — JSON for integrations** provides the report for automation.

| Status | Meaning |
| --- | --- |
| `signal_found` | A technology signal was observed. This does not verify that the tool ran or sent an event. |
| `not_observed` | No matching signal was observed within the checked scope. This does not prove the tool is absent. |
| `inconclusive` | A required check could not be completed. |

Each delivered website has one dataset row. Use `tech_names` for a technology list, `technologies` for categories and available versions, or flat category columns for spreadsheets. `input_url` and `checked_at` help join results to your source list. `page_checks`, `coverage_status` and `next_step` explain incomplete checks. `detection_sources` identifies a page or additional check associated with a finding; it is not a confidence score.

`rendered_check_status` and `rendered_added_count` describe the optional additional check and its new findings. Such checks may be unavailable or rate-limited; existing findings are retained. Fast skips additional checks. Extended enables them unless disabled with `include_rendered_check: false`. `max_rendered_sites` limits these checks per run.

Dataset views focus on Ecommerce & CMS, Analytics & Marketing, Frontend & Frameworks, Infrastructure, Security or Detection Details. JSON preserves nested data; CSV and Excel provide spreadsheet exports.

Optional **Similarweb traffic estimates** add estimated visits, rank, engagement and acquisition channels. Enable `include_similarweb` to request them. Estimates may be unavailable and are not first-party analytics.

The first-run example uses WordPress.org. Some websites refuse cloud requests: Allbirds returned HTTP 403 in the October 2026 checks. These inputs produce diagnostics rather than a guessed technology stack. Optional rendering supplements a readable sparse page; it is not a bypass for a blocked base request.

### Filters, diagnostics and retries

Set `technologies_filter` to names such as Shopify or `categories_filter` to categories such as Ecommerce. A website must match at least one name in each supplied filter. Matching rows retain their full detected stack. Tool checks alone do not filter websites.

Equivalent homepage URLs are checked once. Different paths and query strings remain separate inputs. Invalid, duplicate, filtered, blocked, unreachable and zero-signal inputs appear in `SCAN_ERRORS` and the report.

`SUMMARY` contains run counts. `RETRY_INPUT` preserves your options and lists inputs affected by temporary failures. Check that its `urls` list is non-empty before another run.

`SUMMARY.status` is `complete`, `partial`, `empty` or `source_unavailable`. If every unique input is invalid or unavailable, the run fails after saving diagnostics. A readable zero-signal page or a filter excluding all sites is a valid empty result. Partial runs retain useful rows. A budget stop preserves remaining inputs in `RETRY_INPUT`; no source request is made when the event budget cannot cover a result.

### Pricing

**$0.0015 per delivered website — $1.50 per 1,000 results**, plus startup and Apify platform/proxy usage paid by the user. The startup event costs $0.00005 per GB, with a minimum of one event; at the default 4 GB allocation it is $0.0002. Check the Pricing tab for current charges.

Skipped and failed inputs incur no result event, but their resource usage is billed under your Apify plan. Additional checks can increase usage costs. Apify's maximum total charge setting limits event spending.

### Coverage and automation

Results describe observable website signals at the time of checking. Websites can change; versions are included only when observable. A missing tool is not proof of absence. Page comparison covers up to three pages, not the entire website. `body_truncated` indicates a partly checked page. This service does not verify event delivery, consent behavior, every browser interaction or email-provider configuration.

Run the Actor through Apify's API with the same JSON input, then read its dataset and report. Older saved input options remain supported; new integrations should use the current input schema and select a check profile explicitly.

### REST API, MCP and agent contract

Use this Actor when you already have public domains or page URLs and need a current technology scan. Use [Tech Stack Leads & Lookup](https://apify.com/apivault_labs/tech-stack-lookup) for searching an indexed database. This Actor does not discover prospect URLs, validate tracking events, test cookie consent, inspect all browser network activity or monitor changes across runs.

Start asynchronously with `POST https://api.apify.com/v2/acts/apivault_labs~website-tech-detector/runs`. Authenticate with `Authorization: Bearer <APIFY_TOKEN>` and send the JSON example above. Poll `GET /v2/actor-runs/{runId}` to a terminal status; read `GET /v2/datasets/{defaultDatasetId}/items` and `GET /v2/key-value-stores/{defaultKeyValueStoreId}/records/SUMMARY`. Read `SCAN_ERRORS`, `CHECK_REPORT` and `RETRY_INPUT` even if the run failed. Add `?format=csv&clean=true` to the dataset items endpoint for CSV. Keep credentials in your client configuration.

Connect an authenticated MCP client to:

`https://mcp.apify.com/?tools=apivault_labs/website-tech-detector`

Discover tools with `tools/list`, then invoke `apivault_labs--website-tech-detector` with the same input fields. A short `waitSecs` can return before completion: follow the returned run and storage IDs. Use the discovered `get-dataset-items` and `get-key-value-store-record` tools to read results and diagnostics. Do not rerun solely because the waiting interval elapsed.

Agents should explicitly choose `scan_profile: "fast"` for a quick supplied-page scan. Use `"extended"` for up to three eligible same-host pages and optional rendered enrichment; set `include_rendered_check: false` if you need HTTP-only comparison. Request `include_similarweb: true` only when third-party traffic estimates are wanted. Legacy requests omitting a profile retain legacy enrichment defaults, so specify a profile for predictable time and cost.

For each row verify `tech_count == technologies.length`, `checked_at`, `final_url` and `coverage_status`. Technology fingerprints can include rule implications; `detection_sources` identifies the checked page or additional check, not exact matching evidence, a direct/inferred classification or independent proof of backend software. Report `not_observed` as inconclusive about absence. Rendered checks can return `blocked`, `unavailable`, `rate_limited`, `run_limit` or `time_budget_reached`; these preserve base findings and mark coverage partial. Never label these as full browser coverage.

For reliable automation, store the original input alongside the run ID and retry only non-empty `RETRY_INPUT.urls` after the stated temporary failure or budget restriction is resolved. One delivered row is one `tech-detection` event; skipped inputs and reports incur no result event. Maximum total charge is an event budget; separate platform/proxy usage can still apply.

The service has its own input and output format and is not affiliated with Wappalyzer or BuiltWith. For finding websites in an indexed technology database, see [Tech Stack Leads & Lookup](https://apify.com/apivault_labs/tech-stack-lookup).

# Actor input Schema

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

Paste domains or page URLs, one per line. Up to 500 inputs. Example: wordpress.org. Bot-protected websites may refuse the request.

## `scan_goal` (type: `string`):

Choose a stack overview, a targeted tool check, or a comparison of up to three pages on each website.

## `scan_profile` (type: `string`):

Fast checks the supplied page. Extended checks up to three pages and enables optional additional checks. Extra checks increase time and platform/proxy usage. Neither mode verifies event delivery.

## `target_technologies` (type: `array`):

For Check specific tools, enter at least one catalog name: Shopify, WordPress, Google Analytics, Google Tag Manager, Klaviyo, React or Webflow. Names ignore case. Unknown names produce a clear error; no fuzzy guessing. Optional in other goals.

## `technologies_filter` (type: `array`):

Optional exact technology names, ignoring letter case. A website is included if it uses any listed technology. Its full detected stack remains in the result.

## `categories_filter` (type: `array`):

Optional category names such as CMS, Ecommerce or Analytics. A website is included if it has any listed category. When both filters are set, it must match both.

## `include_versions` (type: `boolean`):

Add a version to a technology when the public response reveals one.

## `include_similarweb` (type: `boolean`):

Optional third-party traffic estimates, not first-party analytics. Off in either check profile unless explicitly enabled. Adds requests and time.

## `timeout_seconds` (type: `integer`):

Maximum time to fetch each website, including redirects.

## `max_pages_per_site` (type: `integer`):

Override the selected profile: 1 to 3 pages per website. Compare pages checks up to three by default, using eligible links on the same host. It may find fewer pages.

## `include_rendered_check` (type: `boolean`):

Additional checks can improve coverage. Fast always skips them. Extended enables them unless disabled. Availability varies; existing findings are retained.

## `max_rendered_sites` (type: `integer`):

Limit how many websites receive an additional check. Availability is not guaranteed.

## Actor input object example

```json
{
  "urls": [
    "https://wordpress.org"
  ],
  "scan_goal": "overview",
  "scan_profile": "fast",
  "include_versions": true,
  "timeout_seconds": 15,
  "max_rendered_sites": 20
}
```

# Actor output Schema

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

One row per unique website with detected technology signals matching the optional filters.

## `check_report` (type: `string`):

Open a readable report with tool answers, page comparison, coverage and next steps. Download or use JSON separately for integrations.

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

Counts and status: complete, partial, empty or source_unavailable. Diagnostics are saved even when no website could be checked and the run fails.

## `retry_input` (type: `string`):

Ready-to-copy input for a new run after temporary failures clear. Do not run an empty urls list.

## `errors` (type: `string`):

Duplicate, filtered, unavailable and empty inputs with a reason for each. Skipped inputs produce no result charge.

## `check_report_json` (type: `string`):

Delivered findings plus diagnostics for skipped or unavailable inputs. Signals are observations, not proof of absence or runtime activity.

# 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://wordpress.org"
    ],
    "scan_goal": "overview",
    "scan_profile": "fast"
};

// Run the Actor and wait for it to finish
const run = await client.actor("apivault_labs/website-tech-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://wordpress.org"],
    "scan_goal": "overview",
    "scan_profile": "fast",
}

# Run the Actor and wait for it to finish
run = client.actor("apivault_labs/website-tech-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://wordpress.org"
  ],
  "scan_goal": "overview",
  "scan_profile": "fast"
}' |
apify call apivault_labs/website-tech-detector --silent --output-dataset

```

## MCP server setup

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