# Google Ads Transparency Monitor (`evocative_kumquat/google-ads-transparency-monitor`) Actor

Get the ads any advertiser runs on Google from the public Ads Transparency Center. Search by domain, advertiser ID or name; filter by country, format and date. $2 per 1,000 ads, free notice rows, and a clean stop with your data when Google rate limits.

- **URL**: https://apify.com/evocative_kumquat/google-ads-transparency-monitor.md
- **Developed by:** [Dylan Caponi](https://apify.com/evocative_kumquat) (community)
- **Categories:** Marketing, 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 $2.00 / 1,000 ad returneds

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

## Google Ads Transparency Monitor

List the ads any advertiser runs on Google, straight from Google's public Ads Transparency Center (adstransparency.google.com). Give it a website domain, an advertiser ID or an advertiser name. You get one row per ad creative: format, first and last shown dates, image or preview link, and a link to the ad's own page on Ads Transparency Center.

$2.00 per 1,000 ads. Notice rows for advertisers that are not found or have no ads are free. When Google rate limits a run, it waits, retries, and if the limit lasts, it stops cleanly with the ads collected so far instead of failing the run.

### What you can use it for

- See which ads a competitor is running right now, and since when.
- Check whether an ad has stopped running (its last shown date stops moving).
- Keep a dated record of an advertiser's ads by running it on a schedule and comparing datasets.
- Pull ads for a list of domains in one run for market or agency research.

### Input examples

By website domain (every ad Ads Transparency Center links to that domain, across all advertiser accounts that use it):

```json
{
    "advertisers": ["nike.com"],
    "maxAdsPerAdvertiser": 40
}
```

By advertiser ID (exact; copy it from the advertiser's page URL on Ads Transparency Center, or paste the whole link):

```json
{
    "advertisers": [
        "AR16735076323512287233",
        "https://adstransparency.google.com/advertiser/AR13872981516994215937?region=US"
    ]
}
```

By advertiser name (resolved through Google's own advertiser suggestions):

```json
{
    "advertisers": ["Blue Bottle Coffee"],
    "nameMatch": "matching"
}
```

With filters: only video ads shown in the United States during October 2026:

```json
{
    "advertisers": ["AR16735076323512287233"],
    "region": "US",
    "format": "VIDEO",
    "startDate": "2026-10-01",
    "endDate": "2026-10-31",
    "maxAdsPerAdvertiser": 200
}
```

You can mix domains, IDs and names in one list.

### Input fields

| Field | What it does |
|---|---|
| `advertisers` | One entry per line: a domain (`nike.com`), an advertiser ID (`AR16735076323512287233`), a link to an advertiser page on Ads Transparency Center, or an advertiser name (`Blue Bottle Coffee`). |
| `region` | Two-letter country code (`US`, `GB`, `DE`, ...) to only return ads shown in that country. Empty means all regions. |
| `format` | `ALL` (default), `TEXT`, `IMAGE` or `VIDEO`. |
| `startDate`, `endDate` | Only ads shown at some point within this date range (YYYY-MM-DD, both days included). An ad that started before the range and is still running counts. |
| `maxAdsPerAdvertiser` | Stop after this many ads per entry (default 40, up to 10,000). Ads come back in the order Ads Transparency Center lists them, most recently shown first. For a name that matches several advertisers, the limit applies to each matched advertiser. |
| `includeDetails` | Off by default. When on, each ad's detail page is also read to add the countries it was shown in (with the last shown date per country) and its variations. One extra request per ad, so runs take much longer. The price per ad does not change. |
| `nameMatch` | For names only. `matching` (default) takes the suggested advertisers whose name matches yours, ignoring case, punctuation and suffixes such as Inc or LLC, or the top suggestion if none match. `all` takes every advertiser Google suggests for that name (up to 10). |
| `maxRateLimitWaitSecs` | Advanced. Total time a run may spend waiting when Google rate limits it (default 240 seconds). |

How each kind of entry is searched:

- Domain: all ads Ads Transparency Center links to that domain, from any advertiser account. A large brand's domain often covers several accounts, for example regional entities.
- Advertiser ID or link: ads from that one advertiser account.
- Name: the name is first resolved to advertiser accounts (see `nameMatch`), then each account's ads are listed. The run log names the other suggested advertisers that were not included. For exact results, use an advertiser ID.

### Output

One dataset row per ad creative. Example:

```json
{
    "query": "AR16735076323512287233",
    "queryType": "advertiserId",
    "status": "ok",
    "message": null,
    "advertiserId": "AR16735076323512287233",
    "advertiserName": "Nike, Inc.",
    "creativeId": "CR10843954190812708865",
    "format": "IMAGE",
    "firstShown": "2026-04-28T16:37:41.000Z",
    "lastShown": "2026-11-05T05:08:18.000Z",
    "regions": ["US"],
    "regionLastShown": [{ "region": "US", "lastShownDate": "2026-11-04" }],
    "variationCount": 3,
    "variationImageUrls": [],
    "domain": null,
    "imageUrl": null,
    "previewUrl": "https://displayads-formats.googleusercontent.com/ads/preview/content.js?...",
    "transparencyUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR10843954190812708865?region=US",
    "scrapedAt": "2026-11-05T05:37:12.232Z"
}
```

| Field | Meaning |
|---|---|
| `query` | The input entry this row came from, as you typed it. |
| `queryType` | `domain`, `advertiserId` or `name`. |
| `status` | `ok` for an ad. Free notice rows use `not_found`, `no_ads` or `error`. |
| `message` | Plain explanation on notice rows; null on ads. |
| `advertiserId`, `advertiserName` | The advertiser account that ran the ad. |
| `creativeId` | Google's ID for the ad creative. |
| `format` | `TEXT`, `IMAGE` or `VIDEO`, as Ads Transparency Center labels it. |
| `firstShown`, `lastShown` | First and last shown dates reported by Ads Transparency Center, in UTC. |
| `regions` | Countries the ad was shown in. Only with `includeDetails`; otherwise null. |
| `regionLastShown` | Last shown date per country. Only with `includeDetails`. |
| `variationCount`, `variationImageUrls` | Number of variations and any variation image links. Only with `includeDetails`. |
| `domain` | Filled when the entry was a domain. |
| `imageUrl` | Direct image link when Google serves the ad as a static image (text ads are often archived this way). |
| `previewUrl` | The script Google uses to render the ad preview, when there is no static image. |
| `transparencyUrl` | Opens the ad on Ads Transparency Center. |
| `scrapedAt` | When the row was collected. |

If an entry finds nothing, the dataset gets one free notice row for it with `status` set to `not_found` (no such advertiser), `no_ads` (the advertiser exists but no ads match your filters) or `error`, and a plain `message`. A run summary (ads per entry, requests made, rate-limit waits) is saved under the `SUMMARY` key of the run's key-value store.

### Pricing

Pay per event, no subscription:

- $0.002 per ad row returned ($2.00 per 1,000 ads).
- $0.00005 per run start (Apify's standard start fee; charged once at the default 512 MB memory, once per GB if you raise the memory).
- Notice rows (`not_found`, `no_ads`, `error`) are free.

Worked example: one run that returns 1,000 ads costs $2.00 plus $0.00005 for the start, so about $2.00. A run that returns 40 ads costs $0.08.

If you set a maximum cost per run, the actor only collects as many ads as fit under it, then stops cleanly. Every ad in the dataset is one you were charged for, and you are never charged for ads that were not delivered.

### Speed and reliability

- Requests go out one at a time, about one per second. Each listing request returns up to 40 ads, so a run without details returns roughly 40 ads per second when Google is not rate limiting. With `includeDetails` on it is about one ad per second.
- Google sometimes rate limits the shared IP addresses Apify runs go out from. The run then waits and retries (20 to 90 seconds per wait). If the limit lasts longer than `maxRateLimitWaitSecs`, the run ends early as a normal finished run with every ad collected so far, adds a free `error` notice row for the entry it was on, and skips the rest. Running again a few minutes later usually works.
- If detail lookups get rate limited, details are switched off for the rest of the run and the remaining ads are still returned, without regions and variations.

### Limits

- Public data only. You get what Ads Transparency Center shows publicly; Google decides which ads, advertisers and regions appear there and how far back they go.
- No login, cookies or proxies are used.
- Big runs are slower, not more expensive per ad: rate limits on Google's side can add waits.
- The listing can change between runs as ads start and stop, and the ad counts Google reports for an advertiser are ranges.
- It does not download video files, read ad text out of rendered previews, return spend or impression numbers (Google does not publish them for regular ads), or handle the separate political ads reports.

# Actor input Schema

## `advertisers` (type: `array`):

One entry per line. Each entry can be a website domain (nike.com), an advertiser ID from Ads Transparency Center (AR16735076323512287233), a link to an advertiser page, or an advertiser name (Blue Bottle Coffee).

## `region` (type: `string`):

Two-letter country code (US, GB, DE, ...) to only return ads shown in that country. Leave empty for all regions.

## `format` (type: `string`):

Only return ads of this format.

## `startDate` (type: `string`):

Only ads shown on or after this date (YYYY-MM-DD).

## `endDate` (type: `string`):

Only ads shown on or before this date (YYYY-MM-DD).

## `maxAdsPerAdvertiser` (type: `integer`):

Stop after this many ads for each entry above. For a domain or a name that matches several advertisers, the limit applies per resolved advertiser for names and per domain for domains. Ads come newest-shown first.

## `includeDetails` (type: `boolean`):

Look up every ad's detail page to add the list of countries it was shown in and its variations. Costs one extra request per ad, so runs take longer. Price per ad is the same.

## `nameMatch` (type: `string`):

How an advertiser name is resolved. 'Matching names' takes the suggested advertisers whose name matches yours (ignoring case, punctuation and suffixes like Inc or LLC), or the top suggestion if none match. 'All suggestions' takes every advertiser Google suggests for the name (up to 10).

## `maxRateLimitWaitSecs` (type: `integer`):

If Google rate limits the run, it waits and retries. This caps the total waiting per run; after that the run ends with the ads collected so far.

## Actor input object example

```json
{
  "advertisers": [
    "nike.com"
  ],
  "region": "",
  "format": "ALL",
  "maxAdsPerAdvertiser": 40,
  "includeDetails": false,
  "nameMatch": "matching",
  "maxRateLimitWaitSecs": 240
}
```

# Actor output Schema

## `ads` (type: `string`):

One dataset row per ad creative, plus an uncharged notice row for any advertiser that was not found or had no ads.

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

Per-input counts and status, stored under the SUMMARY key of the run's key-value store.

# 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 = {
    "advertisers": [
        "nike.com"
    ],
    "maxAdsPerAdvertiser": 40
};

// Run the Actor and wait for it to finish
const run = await client.actor("evocative_kumquat/google-ads-transparency-monitor").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 = {
    "advertisers": ["nike.com"],
    "maxAdsPerAdvertiser": 40,
}

# Run the Actor and wait for it to finish
run = client.actor("evocative_kumquat/google-ads-transparency-monitor").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 '{
  "advertisers": [
    "nike.com"
  ],
  "maxAdsPerAdvertiser": 40
}' |
apify call evocative_kumquat/google-ads-transparency-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,evocative_kumquat/google-ads-transparency-monitor"
        }
    }
}
```

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/Ae8t9CAIQDhrMIkO5/builds/0sltJVCgb4ZJweKbP/openapi.json
