# Ad Tracking Gap Checker (`proficientstack/ad-tracking-gap-checker`) Actor

Finds online stores that pay for ads but cannot measure them: no Meta pixel, no tag manager, no GA4/Google Ads tag on the homepage. Reports only what is verifiable in the page source, and says how to confirm it in ten seconds.

- **URL**: https://apify.com/proficientstack/ad-tracking-gap-checker.md
- **Developed by:** [Gabriel Barreto](https://apify.com/proficientstack) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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

## Ad Tracking Gap Checker

Finds online stores that are paying for ads but **cannot measure them** — no Meta pixel, no tag manager, no Google Analytics or Google Ads tag on the homepage.

Give it a list of domains. It returns, for each one, what is missing, how bad it is, and **how to confirm it yourself in ten seconds**. You are only charged for sites where there is a real, verifiable finding.

### Who this is for

- **Agencies and freelancers** building a prospect list: a store running ads with no pixel is a conversation that starts with a fact, not a pitch.
- **Anyone auditing their own portfolio** of stores, landing pages or client sites after a migration or a theme change.

### What it will not do

This is the part that matters, because a scanner that overreports is worse than no scanner at all. **Three guards stop false findings**, and two of them exist because the naive version got them wrong:

1. **A purchase event never fires on a homepage.** `fbq('track', 'Purchase')` belongs on the thank-you page. Reporting "no purchase event" from the homepage would be false, so it is not reported.
2. **A tag manager can inject the pixel at runtime.** If GTM is present but no inline pixel, the honest answer is *indeterminate* — not a finding, and not charged.
3. **A consent manager can load every tag after consent, or server-side.** Found while testing against `shopify.com`: 726 KB of homepage and zero tracking signals in the source. The site measures perfectly well; it simply loads tags behind its own cookie banner. Any consent platform or tag loader present ⇒ *indeterminate*.

Everything the Actor claims is claimed about **the HTML of the homepage**, and the output says so in those words.

### Input

| Field | Type | Description |
|---|---|---|
| `urls` | string list | Domains or full URLs, one per line. `example.com` works; so does `https://example.com/`. |
| `onlyTargets` | boolean | Return only sites with a verifiable gap. Off by default. |
| `maxConcurrency` | integer | How many sites to fetch at once. Default 8. |

```json
{
    "urls": ["allbirds.com", "example.com"],
    "onlyTargets": false,
    "maxConcurrency": 8
}
```

### Output

One row per site:

| Field | Meaning |
|---|---|
| `finding` | What is missing, in plain words. Empty when there is nothing to report. |
| `severity` | `1` = no pixel and no tag manager (worst). `2` = no Google tags at all. `8` = indeterminate. `9` = measurement found. |
| `how_to_verify` | The exact string to search for in View Source. |
| `consent_or_loader` | Whether a consent manager or tag loader was detected. |
| `meta_pixel`, `ga4`, `gtm`, `google_ads`, `tiktok` | Raw per-signal detection. |
| `status_code`, `error` | HTTP status; network or TLS failures are reported rather than hidden. |

Example row:

```json
{
    "name": "example.com",
    "url": "https://example.com",
    "finding": "no Meta pixel and no tag manager on the homepage",
    "severity": 1,
    "is_target": true,
    "how_to_verify": "Open the site, View Source, search for \"connect.facebook.net\" and \"GTM-\". Neither is there.",
    "consent_or_loader": "no",
    "status_code": 200
}
```

### Pricing

Pay per finding. Sites that measure correctly, sites where the answer is indeterminate, and sites that fail to load are all returned in the dataset **free of charge** — you pay only for rows you can act on.

### Notes

TLS certificates are verified. An invalid certificate is not noise to be skipped: it is a finding in its own right, and it appears in the `error` field.

# Actor input Schema

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

Store homepages. Paste domains (example.com) or full URLs, one per line.

## `onlyTargets` (type: `boolean`):

Skip sites that measure correctly and sites where the answer is indeterminate.

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

How many sites to fetch at the same time.

## Actor input object example

```json
{
  "urls": [
    "allbirds.com",
    "shopify.com",
    "example.com"
  ],
  "onlyTargets": false,
  "maxConcurrency": 8
}
```

# Actor output Schema

## `findings` (type: `string`):

One row per site: what measurement tag is missing, how severe it is, and how to confirm it in the page source in ten seconds. Sites that measure correctly, sites where a consent manager may load tags later, and network errors are all reported too, at no charge.

# 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": [
        "allbirds.com",
        "shopify.com",
        "example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("proficientstack/ad-tracking-gap-checker").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": [
        "allbirds.com",
        "shopify.com",
        "example.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("proficientstack/ad-tracking-gap-checker").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": [
    "allbirds.com",
    "shopify.com",
    "example.com"
  ]
}' |
apify call proficientstack/ad-tracking-gap-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,proficientstack/ad-tracking-gap-checker"
        }
    }
}
```

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/aXHv6SFDtCb8WZkDh/builds/OHXA3KpXtcelTBYzw/openapi.json
