# Website Tracking Pixel Scanner (`automation-lab/website-tracking-pixel-scanner`) Actor

Scan public websites for advertising and analytics tags, exposed pixel IDs, script evidence, and browser network evidence.

- **URL**: https://apify.com/automation-lab/website-tracking-pixel-scanner.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.36 / 1,000 page extracteds

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 Tracking Pixel Scanner

Audit **website tracking** across public pages with a real browser.

Website Tracking Pixel Scanner detects advertising pixels, analytics tags, tag managers, session analytics, and marketing-automation scripts.
It exports provider-level records with exposed tag IDs, sanitized script or network evidence, the final page URL, scan mode, status, and UTC timestamp.

Use it as a website tracking checker for one page, a client portfolio, or a recurring marketing-stack audit.
No login, website integration, or private account is required.

### What does Website Tracking Pixel Scanner do?

The Actor opens each supplied public URL in an isolated Chromium context.
During the scan it:

1. observes browser network requests;
2. inspects external and inline script elements;
3. inspects bounded rendered HTML;
4. optionally clicks only a clearly labelled consent control;
5. matches supported provider signatures;
6. extracts a public tag, pixel, measurement, partner, or account ID when exposed;
7. emits evidence-backed dataset rows.

A successful page with no supported signal receives an explicit `no-tracking-signals` row.
A page that cannot be loaded receives an `error` row instead of a false negative.

### Who is it for?

#### Marketing operations teams

Verify that expected analytics and conversion tags are present after a launch, redesign, or tag-manager change.

#### Privacy and compliance teams

Create a repeatable inventory of observable third-party tracking signals for a broader review.
The Actor is evidence collection, not a legal compliance certification.

#### Agencies

Audit client domains on demand or on an Apify Schedule and export a consistent dataset for reporting.

#### Sales and lead-enrichment teams

Identify publicly observable marketing-stack providers before outreach.

#### Developers and QA teams

Check deployment evidence, exposed IDs, redirects, HTTP status, and consent behavior in an automated workflow.

### Supported tracking providers

The initial detector covers these provider families:

| Category | Providers |
| --- | --- |
| Tag manager | Google Tag Manager |
| Analytics | Google Analytics, Adobe Analytics, Matomo, Segment, Mixpanel |
| Advertising | Google Ads, Meta Pixel, TikTok Pixel, LinkedIn Insight Tag, Microsoft Advertising UET, Pinterest Tag, Snap Pixel, X Pixel, Reddit Pixel, Quora Pixel |
| Session analytics | Hotjar, Microsoft Clarity |
| Marketing automation | HubSpot, Pardot / Account Engagement |

Coverage is signature-based and intentionally conservative.
A provider can change its scripts, endpoints, or identifier format without notice.

### What data does the Actor return?

Each provider or exposed provider ID becomes a separate row.
The dataset also includes one typed no-signal or error row when appropriate.

| Field | Meaning |
| --- | --- |
| `inputUrl` | Normalized submitted URL |
| `pageUrl` | Final URL after redirects |
| `domain` | Final hostname |
| `status` | `detected`, `no-tracking-signals`, or `error` |
| `isPrimaryResult` | `true` for one billable page result, `false` for included supporting evidence, or `null` for uncharged errors |
| `provider` | Detected provider, or `null` for no-signal/error rows |
| `category` | Analytics, advertising, tag manager, marketing automation, or session analytics |
| `tagId` | Publicly exposed identifier when available |
| `evidenceType` | `network`, `script`, or `html` |
| `evidenceUrl` | Sanitized supporting URL with nonessential query values removed |
| `evidencePattern` | Human-readable matched signature |
| `scanMode` | `browser-network` |
| `pageTitle` | Rendered title |
| `httpStatus` | Main-document response status |
| `consentAction` | `clicked`, `not-found`, or `disabled` |
| `requestCount` | Browser requests observed |
| `scannedAt` | ISO 8601 UTC scan timestamp |
| `error` | Concise failure reason, otherwise `null` |

### Example output

This abbreviated record reflects current browser-network behavior; the public tag ID is anonymized in the documentation.

```json
{
  "inputUrl": "https://www.apify.com/",
  "pageUrl": "https://apify.com/",
  "domain": "apify.com",
  "status": "detected",
  "isPrimaryResult": true,
  "provider": "Google Tag Manager",
  "category": "Tag manager",
  "tagId": "GTM-ABC1234",
  "evidenceType": "network",
  "evidenceUrl": "https://www.googletagmanager.com/gtm.js?id=GTM-ABC1234",
  "evidencePattern": "Google Tag Manager resource",
  "scanMode": "browser-network",
  "pageTitle": "Apify: Marketplace of ready-to-run tools for AI",
  "httpStatus": 200,
  "consentAction": "not-found",
  "requestCount": 380,
  "scannedAt": "2026-09-19T04:25:03.278Z",
  "error": null
}
```

One page can produce multiple evidence rows.
Exactly one successful row per page has `isPrimaryResult: true`; supporting provider/ID rows have `isPrimaryResult: false` and are explicitly non-billable.
Billing remains once per successfully loaded page, not once per dataset row.

### How to scan a website for tracking pixels

1. Open the Actor in Apify Console.
2. Add one or more public URLs to **Website URLs**.
3. Keep **Try to accept consent banners** enabled when you want consent-gated tags to load.
4. Keep the default three-second observation window for ordinary pages.
5. Start the run.
6. Open the **Tracking evidence** dataset view.
7. Filter by `provider`, `category`, `tagId`, or `status`.
8. Export JSON, CSV, Excel, XML, or another Apify-supported format.

Small inputs are the best way to validate the workflow before scheduling a larger portfolio.

### Input parameters

#### `startUrls`

Required array of public HTTP or HTTPS pages.
Strings and request-list objects with a `url` field are accepted.
Credential-bearing, local, and private-network targets are rejected.

#### `maxPages`

Maximum submitted pages to scan.
The default is 10 and the maximum is 100.
Exact duplicate normalized URLs are scanned once.

#### `maxConcurrency`

Parallel isolated browser pages.
The default is 2 and the maximum is 4.
Lower concurrency can help slow or fragile websites.

#### `navigationTimeoutSecs`

Initial navigation timeout from 5 to 90 seconds.
The default is 30 seconds.
A failed navigation receives one bounded retry in a fresh context.

#### `waitAfterLoadSecs`

Observation time after DOM content loads and the optional consent action finishes.
The default is 3 seconds and the maximum is 15 seconds.
Increase it only for tags known to initialize late.

#### `clickConsentBanner`

When enabled, the scanner tries a small set of unambiguous labels such as **Accept all**, **Allow all**, **Agree**, **Continue**, or **OK**.
It does not guess at ambiguous controls.

#### `maxEvidencePerProvider`

Maximum exposed IDs retained for one provider on one page.
The default is 10 and the maximum is 50.

### Example input

```json
{
  "startUrls": [
    { "url": "https://www.apify.com" },
    { "url": "https://www.hubspot.com" },
    { "url": "https://segment.com" }
  ],
  "maxPages": 3,
  "maxConcurrency": 2,
  "waitAfterLoadSecs": 3,
  "clickConsentBanner": true
}
```

This is a useful recurring audit input because it exercises multiple analytics, advertising, and marketing-provider signals.

### How much does it cost to scan website tracking pixels?

The Actor uses pay per event.

- **Run started:** $0.005 once per run.
- **Page scanned:** BRONZE price $0.0056 for each successfully loaded page.
- Failed page loads produce a typed error row but do not incur the page event.
- Multiple provider evidence rows from one page do not create multiple page charges.

Example BRONZE estimates:

| Successfully scanned pages | Estimated price |
| ---: | ---: |
| 1 | $0.0106 |
| 10 | $0.061 |
| 25 | $0.145 |
| 100 | $0.565 |

The platform displays the applicable tier before a run.
Examples are estimates and can be affected by refunds, fraud, disputes, taxes, corrections, or clawbacks.

### Recurring privacy and marketing-stack audits

For monitoring, create an Apify Schedule with a stable URL list.
Export each run's dataset to your data warehouse, spreadsheet, webhook, Make scenario, or Zapier workflow.
Compare records by:

- `domain`;
- `provider`;
- `tagId`;
- `status`;
- `scannedAt`.

A new row can indicate a deployed provider or exposed identifier.
A missing row can indicate removal, consent differences, a changed signature, or a page-load problem, so compare `status` and `error` before drawing conclusions.

### Integration patterns

#### Deployment QA

Run after a website release and assert that the expected GTM, GA4, or advertising ID appears.

#### Client portfolio reporting

Scan a bounded domain list weekly and group output by provider and category.

#### CRM enrichment

Map domains to observed provider records and store the latest `scannedAt` timestamp with the evidence.

#### Privacy review intake

Use the output as a technical inventory for a qualified privacy professional.
Do not treat detection as a legal verdict.

### Run with the Apify API

Replace `<APIFY_TOKEN>` with a secret or environment variable; never commit it.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~website-tracking-pixel-scanner/runs?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url": "https://www.apify.com"}],
    "maxPages": 1,
    "clickConsentBanner": true
  }'
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/website-tracking-pixel-scanner').call({
  startUrls: [{ url: 'https://www.apify.com' }],
  maxPages: 1,
  clickConsentBanner: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/website-tracking-pixel-scanner').call(run_input={
    'startUrls': [{'url': 'https://www.apify.com'}],
    'maxPages': 1,
    'clickConsentBanner': True,
})

items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with Apify MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/website-tracking-pixel-scanner"
```

#### Claude Desktop

Use this JSON configuration in Claude Desktop:

```json
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=automation-lab/website-tracking-pixel-scanner"
    }
  }
}
```

#### Cursor

Add the same HTTP MCP server URL to Cursor's MCP settings and name it `apify`.

#### VS Code

Add the same HTTP MCP server URL to your VS Code MCP configuration and enable the `apify` server.

Example prompts:

- “Scan apify.com and list detected advertising pixels with public IDs and evidence.”
- “Audit these three client pages and separate detected, no-signal, and error results.”
- “Compare provider and tag ID records from this run with last week's dataset.”

### Detection quality and evidence

Network evidence is usually strongest because it shows a resource or beacon requested by the rendered page.
Script evidence identifies loaded script URLs or bounded inline initialization code.
HTML evidence identifies signatures present in the rendered document.

The scanner prefers network evidence and preserves distinct exposed IDs.
It does not export arbitrary script bodies or arbitrary query-string values.
This minimizes irrelevant page data while keeping the audit trace useful.

### Limits

- The Actor scans only submitted pages; it does not crawl an entire site automatically.
- It does not log in, solve CAPTCHAs, or bypass access controls.
- It has no automatic proxy fallback.
- It does not execute post-login or checkout-only journeys.
- Tags triggered only by scrolling, video, form submission, or another custom interaction may not appear.
- A strict consent wall can prevent some tags from loading.
- Browser or provider changes can require signature updates.
- `no-tracking-signals` means no supported signal was observed during this scan, not proof that a site performs no tracking.
- Tracking pixels in emails, mobile apps, server-side APIs, or DNS records are outside scope.
- This is not an Amazon price tracker despite unrelated “website tracking amazon prices” search language.

### Legality

Submit only anonymously reachable public URLs that you are authorized to scan.
Respect website terms, robots guidance where applicable, rate limits, and local law.
Do not use the Actor to probe private infrastructure or evade access controls.

The Actor rejects URL credentials and private or local network targets.
Redirects and browser subresources are checked against public DNS addresses.
Each page receives a fresh browser context, and no website login data is persisted.

Public tracking IDs can still be business identifiers.
Apply appropriate retention and access controls to exported datasets.

### Troubleshooting

#### The result says `no-tracking-signals`

Confirm that the correct page was submitted.
Try enabling consent handling and increasing `waitAfterLoadSecs` modestly.
The tag may also require an interaction the Actor does not perform or may use an unsupported provider.

#### The result says `error`

Review `httpStatus` and `error`.
The site may be unavailable, blocked, too slow, or inaccessible from the run location.
A failed scan is not treated as a no-tracker verdict.

#### The expected ID is null

A provider can be detected without exposing its identifier in the request or script text.
The provider and evidence remain useful, while `tagId` truthfully stays null.

#### Too many or too few records

One page can return several providers and several IDs for one provider.
Use `maxEvidencePerProvider` to cap exposed IDs.
Remember that billing is per successfully scanned page, not per evidence row.

#### Consent was not clicked

The Actor only uses clear English control labels.
Localized, shadow-DOM, iframe, or custom banners may be reported as `not-found`.
This conservative behavior avoids clicking unrelated page controls.

### FAQ

#### How does a tracking pixel work?

A tracking pixel or tag causes the browser to load a script, image, or network endpoint associated with an analytics or advertising provider.
The request can carry a public measurement or pixel identifier.
This Actor observes those public browser-side signals and exports structured evidence.

#### Does the Actor find every tracker?

No.
It covers a documented provider set and a bounded page-load journey.
Server-side tracking and unsupported signatures are not visible.

#### Does it crawl all pages on a domain?

No.
Provide every page you need to audit.
This keeps scope, cost, and provenance explicit.

#### Are failed pages charged as page scans?

No.
The one-time start event still applies, but a typed page error does not emit the `page` charge event.

#### Can I schedule it?

Yes.
Use an Apify Schedule and retain run datasets for change comparison.

#### Can I export to CSV or Excel?

Yes.
Use the dataset export controls or API endpoints provided by Apify.

#### Is this a GDPR compliance certificate?

No.
It supplies technical evidence that can support a review by qualified professionals.

### Related Automation Lab Actors

- [TikTok & Kwai Ad Pixel Checker](https://apify.com/automation-lab/tiktok-kwai-domain-advertiser-checker) — a narrower HTTP-first domain checker for TikTok and Kwai advertising signals, with GTM evidence and fetch diagnostics.

Choose this Website Tracking Pixel Scanner when you need browser-network evidence across a broader provider set.
Choose the related checker when your workflow specifically focuses on TikTok/Kwai advertiser qualification and prefers one company-level verdict row.

### Support

When reporting a reproducible problem, include:

- a public URL that demonstrates it;
- the run link;
- expected provider or identifier;
- actual `status`, `evidencePattern`, and `error` fields;
- whether consent handling was enabled.

Do not include private credentials, session cookies, or personal data.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/website-tracking-pixel-scanner/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

Public HTTP or HTTPS pages to scan. Each page is opened in an isolated browser context; private-network and credential-bearing URLs are rejected.

## `maxPages` (type: `integer`):

Maximum number of submitted pages to scan. Duplicate URLs are scanned once.

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

Number of isolated pages scanned in parallel. Keep the default for reliable tracking-network capture.

## `navigationTimeoutSecs` (type: `integer`):

Maximum time allowed for initial page navigation before a bounded retry with a fresh browser context.

## `waitAfterLoadSecs` (type: `integer`):

Time to observe scripts and network requests after DOM content loads and the optional consent click finishes.

## `clickConsentBanner` (type: `boolean`):

Click a clearly labelled accept, allow, agree, continue, or OK control when found so consent-gated tags can load. Ambiguous controls are ignored.

## `maxEvidencePerProvider` (type: `integer`):

Caps duplicate network, script, and HTML evidence while retaining exposed identifiers.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.apify.com"
    }
  ],
  "maxPages": 10,
  "maxConcurrency": 2,
  "navigationTimeoutSecs": 30,
  "waitAfterLoadSecs": 3,
  "clickConsentBanner": true,
  "maxEvidencePerProvider": 10
}
```

# Actor output Schema

## `dataset` (type: `string`):

Detected providers, exposed IDs, evidence URLs, page provenance, and scan status.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.apify.com"
        }
    ],
    "maxPages": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/website-tracking-pixel-scanner").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 = {
    "startUrls": [{ "url": "https://www.apify.com" }],
    "maxPages": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/website-tracking-pixel-scanner").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 '{
  "startUrls": [
    {
      "url": "https://www.apify.com"
    }
  ],
  "maxPages": 10
}' |
apify call automation-lab/website-tracking-pixel-scanner --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/website-tracking-pixel-scanner"
        }
    }
}
```

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/61IOdcjxlFfb8FDLI/builds/dUA5CM9sctFm7jrbt/openapi.json
