# Google Ads Transparency Center Scraper (`zovo-one/google-ads-transparency-scraper`) Actor

Get the ads an advertiser runs on Google, up to 5,000 per input line. Search by name, ID or domain and filter by region, date, format and platform. Each ad has format, first/last shown, days shown, image or preview URL, text where shown, landing domain. Optional per-region dates and impressions.

- **URL**: https://apify.com/zovo-one/google-ads-transparency-scraper.md
- **Developed by:** [Michael Lip](https://apify.com/zovo-one) (community)
- **Categories:** Marketing, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 Center Scraper

Get the ads any advertiser runs on Google as clean JSON rows, from $0.0012 per ad, by name, advertiser ID or website domain.

The data comes from the public [Google Ads Transparency Center](https://adstransparency.google.com). The Actor reads the same JSON endpoints that page uses, with no browser and no login. In a test run on 2026-11-05 it saved 50 Nike ads with 2 requests to Google.

Use it to see what a competitor is running and for how long, to collect creatives from a whole category, to watch an advertiser on a schedule, or to find resellers and affiliates that send ad traffic to your domain.

### What you get

One dataset row per ad. The first group of fields is always there. The second group is filled only when you turn on Include ad details.

| Field | Type | Meaning |
|---|---|---|
| `advertiserId` | string | Google's advertiser ID (`AR...`) |
| `advertiserName` | string or null | The advertiser's legal name as Google lists it |
| `creativeId` | string | Google's ID of the ad (`CR...`) |
| `format` | string or null | `text`, `image` or `video` |
| `firstShown`, `lastShown` | ISO timestamp (UTC) or null | When Google first and last showed the ad. For a running ad, `lastShown` is recent |
| `daysShown` | number or null | Days the ad was shown, as Google reports it |
| `landingDomain` | string or null | Domain the ad sends traffic to, when Google lists it |
| `imageUrl`, `width`, `height` | string, number or null | Image of the ad. Google shows many text ads as an image, so text ads often have one too |
| `previewUrl` | string or null | Google's preview script (`content.js`) for ads without a direct image, such as most video ads |
| `headline`, `description`, `displayUrl` | string or null | Text ad copy, only when Google puts it as plain fields in the preview URL. On real ads this is rare, so expect `null` most of the time |
| `adUrl` | string | The ad's page in the Ads Transparency Center |
| `regionFilter`, `platformFilter` | string | The region and platform you searched with |
| `query`, `queryType` | string | The input line that found the ad, and how it was read (`name`, `id`, `creative` or `domain`) |
| `scrapedAt` | ISO timestamp | When the row was saved |
| `regions` | array or null | Details only. One entry per region where the ad ran, with `region` (2-letter code, `null` for areas smaller than a country), `regionId`, `firstShown`, `lastShown`, `impressionsMin`, `impressionsMax`. Google adds first dates and impression ranges mainly for EU regions |
| `platforms` | array or null | Details only. Platforms in Google's reach breakdown, such as `SEARCH`, `SHOPPING`, `YOUTUBE`. Often empty for ads shown only outside the EU |
| `impressionsMin`, `impressionsMax` | number or null | Details only. Google's total impression range. `impressionsMin` is `null` when Google gives only an upper bound such as "up to 1,000" |
| `variationCount`, `imageUrls` | number, array or null | Details only. Number of creative variations and their image URLs |
| `detailError` | string or null | Details only. Why the detail lookup failed. The ad is still saved and the lookup isn't charged |

The dataset has two views in Console, Ads (with image previews) and Regions and reach.

Each run also writes a report to the key-value store record `OUTPUT`. It has one entry per input line with the advertiser it resolved to, ads saved, Google's estimate of matching ads (`totalEstimate`, for example 50000 to 60000 for `nike.com`) and the error if the line failed.

### Example output

This row is real. It comes from run `c5A1NgmRygXZXu9Z8` on 2026-11-05 with input `nike.com`, region `anywhere` and details off.

```json
{
  "advertiserId": "AR16735076323512287233",
  "advertiserName": "Nike, Inc.",
  "creativeId": "CR06692121344286392321",
  "format": "text",
  "firstShown": "2023-11-16T21:49:06.000Z",
  "lastShown": "2026-11-05T11:22:35.000Z",
  "daysShown": 885,
  "landingDomain": "nike.com",
  "imageUrl": "https://tpc.googlesyndication.com/archive/simgad/11274417169112350865",
  "previewUrl": null,
  "width": 348,
  "height": 305,
  "headline": null,
  "description": null,
  "displayUrl": null,
  "adUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR06692121344286392321",
  "regionFilter": "anywhere",
  "platformFilter": "all",
  "query": "nike.com",
  "queryType": "domain",
  "scrapedAt": "2026-11-05T11:40:37.956Z"
}
```

With Include ad details on, each row gets these extra fields. They're from a test run on 2026-11-05 with input `nike.com`, region `DE`, for ad `CR10056063563010670593` of Nike Retail BV.

```json
{
  "regions": [
    { "region": "NL", "regionId": 2528, "firstShown": "2023-03-12", "lastShown": "2024-02-23", "impressionsMin": null, "impressionsMax": 1000 },
    { "region": "PL", "regionId": 2616, "firstShown": "2023-03-01", "lastShown": "2026-11-05", "impressionsMin": 5000000, "impressionsMax": 6000000 }
  ],
  "platforms": ["SEARCH", "SHOPPING", "YOUTUBE"],
  "impressionsMin": 5000000,
  "impressionsMax": 6000000,
  "variationCount": 3,
  "imageUrls": [],
  "detailError": null
}
```

### Pricing

You pay per result. There's no subscription and no charge for compute.

| Event | Price | When it's charged |
|---|---|---|
| `ad` | $0.0012 | Each ad row saved, after filters and duplicate removal |
| `ad-detail` | $0.002 | Each successful detail lookup, only with Include ad details on |

Some worked examples.

| Job | Math | Cost |
|---|---|---|
| The prefilled first run (20 ads) | 20 × $0.0012 | $0.024 |
| 1,000 ads | 1,000 × $0.0012 | $1.20 |
| 1,000 ads with details | 1,000 × ($0.0012 + $0.002) | $3.20 |
| 10 competitors, 200 ads each | 2,000 × $0.0012 | $2.40 |

You aren't charged for advertisers that aren't found or fail, for the same ad found by two input lines, for ads your filters drop, or for failed detail lookups. Set a maximum cost per run (`maxTotalChargeUsd` in the API) and the Actor stops before a row it can't pay for in full, then says so in the run report.

### Quick start in Console

1. Open the Actor and click Start. The input is prefilled with `nike.com`, region US and 20 ads, so the first run costs about $0.02 and takes a few seconds.
2. Open the Ads view of the dataset, or export it as JSON, CSV or Excel.
3. Swap in your own advertisers, one per line, and raise "Max ads per advertiser".

### Use it from the API

This call runs the Actor and returns the rows in one response. Sync calls wait up to 300 seconds, so for big jobs start an async run and read the dataset when it finishes.

```bash
curl -X POST "https://api.apify.com/v2/acts/zovo-one~google-ads-transparency-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "advertisers": ["nike.com", "AR16735076323512287233"],
    "region": "US",
    "dateFrom": "90 days",
    "format": "video",
    "maxAdsPerAdvertiser": 100,
    "includeDetails": false
  }'
```

### Use it from Python

```bash
pip install apify-client
```

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("zovo-one/google-ads-transparency-scraper").call(run_input={
    "advertisers": ["nike.com", "Adidas AG"],
    "region": "US",
    "maxAdsPerAdvertiser": 100,
})

for ad in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(ad["advertiserName"], ad["format"], ad["daysShown"], ad["adUrl"])
```

### Use it from Node.js

```bash
npm install apify-client
```

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('zovo-one/google-ads-transparency-scraper').call({
    advertisers: ['nike.com', 'Adidas AG'],
    region: 'US',
    maxAdsPerAdvertiser: 100,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);
```

### Use it from AI agents (MCP)

AI agents can call this Actor as a tool through the [Apify MCP server](https://mcp.apify.com). Each client adds servers in its own way. VS Code and Claude Desktop, for example, don't take the JSON below as written. For your client, open the [MCP configurator](https://mcp.apify.com), pick this Actor and copy the setup it gives you. A client that reads an `mcpServers` block with a `url` key, such as Cursor, can use this config.

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=zovo-one/google-ads-transparency-scraper"
    }
  }
}
```

On the first connection your browser opens so you can sign in to Apify. To skip that, add the header `"Authorization": "Bearer <APIFY_TOKEN>"` to the server config.

Without the `tools` parameter, an agent can still find the Actor with `search-actors`, run it with `call-actor`, and read the rows with `get-dataset-items`.

Here's a prompt that works well.

```text
Use the Google Ads Transparency scraper to get up to 50 video ads that nike.com
ran in the US in the last 90 days. Sort them by daysShown and tell me which
5 ran the longest, with their adUrl.
```

### Input

| Field | What it does | Example |
|---|---|---|
| `advertisers` | Required. One per line, up to 100 advertisers: a name, an advertiser ID (`AR...`), a domain, or an Ads Transparency Center URL | `["nike.com", "AR16735076323512287233", "Adidas AG"]` |
| `region` | 2-letter country code, or `anywhere`. Default `anywhere` | `"US"` |
| `dateFrom` | Only ads shown on or after this date. `YYYY-MM-DD` or relative (`30 days`, `3 months`) | `"90 days"` |
| `dateTo` | Only ads shown on or before this date. Needs `dateFrom`. Empty means today | `"2026-06-30"` |
| `format` | `all`, `text`, `image` or `video`. Default `all` | `"video"` |
| `platform` | `all`, `SEARCH`, `YOUTUBE`, `SHOPPING`, `MAPS` or `PLAY`. Default `all` | `"YOUTUBE"` |
| `maxAdsPerAdvertiser` | Ads to save per input line, 1 to 5,000. Default 50 | `200` |
| `includeDetails` | Adds regions, per-region dates, impression ranges, platforms and creative variations. One extra request per ad, charged as `ad-detail`. Default off | `true` |
| `proxyConfiguration` | Apify Proxy is on by default. Pick the RESIDENTIAL group if Google blocks the run | `{"useApifyProxy": true}` |
| `maxConcurrency` | Advertisers read in parallel, 1 to 3. Default 2 | `2` |

How each kind of input line is read.

- An advertiser ID or a Transparency Center advertiser URL (`https://adstransparency.google.com/advertiser/AR...`) reads that advertiser. It's the most precise choice.
- A domain (`nike.com`, `https://www.nike.com/us`) returns ads from each advertiser that sends traffic to it. For `nike.com` that's "Nike, Inc." plus Nike's regional companies, and it can include resellers. Unicode domains are sent in their ASCII form.
- A name must match an advertiser name exactly, ignoring case, accents, punctuation, `&` versus `and`, a leading "The" and up to two company suffixes such as Inc or GmbH. So `nike inc` matches "Nike, Inc.", but `Coca` doesn't match "Coca-Cola". When several advertisers share the name, the one with the most ads is read and the rest are listed in `OUTPUT`. When nothing matches, the run report lists the closest names with their IDs.
- An ad URL (`.../advertiser/AR.../creative/CR...`) saves only that one ad, if it's among the first 400 ads Google lists for that advertiser with your filters.

A line that can't be read is reported in `OUTPUT` and the other lines still run.

### Limits

- Up to 100 advertisers and 1,000 input lines per run. Split bigger lists into several runs.
- Up to 5,000 ads per input line. A domain or advertiser with more matching ads returns the same first 5,000 each time, so narrow the region, format, platform or dates to reach others.
- Google's date filter covers about the last 12 months. A range that ends before that is rejected with an explanation. For older ads, leave the dates empty and use `firstShown` and `lastShown`.

The Actor reads 40 ads per request, spaced at least 0.3 seconds apart with Apify Proxy and 1 second without. Details add one request per ad. A blocked request is retried up to 5 times with a new proxy session.

Two breakers keep a bad run short. After 3 failed detail lookups in a row, the rest of the ads are saved without details. Those rows still cost the `ad` price, but not `ad-detail`. After 3 advertisers in a row fail, the run stops and marks the remaining lines as skipped.

Near the run timeout the Actor stops, keeps what it saved and still writes `OUTPUT`. If the platform restarts a run, ads already saved are skipped and not charged again. Ads aren't remembered between runs, though. For monitoring, drop `creativeId` values you've already seen on your side.

There's no OCR and no video download. When Google shows a text ad only as an image, the text is in `imageUrl`. Video ads come with `previewUrl`.

### FAQ

#### Why did a domain return ads from several advertisers

A domain search returns each advertiser that sends traffic to it. That can be the brand, its regional companies, resellers or affiliates. Filter on `advertiserId`, or use the advertiser ID as input.

#### A name wasn't found, but the advertiser exists

Names have to match exactly, apart from case, accents, punctuation and company suffixes. Open the `OUTPUT` record. It lists the closest names with their IDs, so you can rerun with the ID or the domain.

#### How do the date filters work

An ad is kept when it was shown at any time in your range. So it ended on or after "Shown since" and started on or before "Shown until". All dates are UTC.

#### How do I watch a competitor every day

Schedule the Actor in Console with "Shown since" set to `2 days`. Each run returns the ads that are new or still running, and you pay only for those rows.

#### What if Google blocks the run

If no ad was saved yet, the run fails with a clear message and nothing is charged. If the block comes partway through, the ads saved before it are kept and charged, and `OUTPUT` lists the advertisers that failed. Open the Proxy setting and pick the RESIDENTIAL group, then run it again.

#### Is this legal

The Actor reads data Google publishes for public transparency, with no login. It collects advertiser names and ads, not data about people. You're responsible for how you use the data and for following Google's terms in your use case. This Actor isn't affiliated with, endorsed by or sponsored by Google.

### Support

Open an issue in the Actor's Issues tab with the run ID and your input. The Transparency Center endpoints aren't an official API and Google can change them. When Google answers in a shape the Actor doesn't know, that advertiser gets an error in the run report instead of an empty result, so please report it and it'll get fixed.

# Changelog

This Actor's version history is a separate document: https://apify.com/zovo-one/google-ads-transparency-scraper/changelog.md

# Actor input Schema

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

Who to look up, one per line. Each line can be a website domain (nike.com), an exact advertiser name (Nike, Inc.), an advertiser ID (AR16735076323512287233) or an Ads Transparency Center URL. A domain returns the ads of every advertiser that sends traffic to it, which can include regional companies and resellers. A name must match exactly, but case, accents, punctuation, & vs and, and suffixes such as Inc or GmbH are ignored; if no name matches, the run report (OUTPUT) lists the closest names and their IDs. An ad URL (.../advertiser/AR.../creative/CR...) saves only that ad, if it is among the first 400 ads Google lists for that advertiser with your filters. Up to 100 advertisers per run (at most 1,000 lines in total, counting lines that cannot be read). A line that cannot be read is reported and the other lines still run.

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

Country where the ads were shown, as a 2-letter code (US, GB, DE, FR, JP; UK also works), or "anywhere" for all regions. Empty means anywhere. Example: US

## `dateFrom` (type: `string`):

Only ads shown on or after this date. Use YYYY-MM-DD (2026-01-01) or a relative value such as "30 days", "2 weeks", "3 months" or "1 year". Google's date filter covers about the last 12 months. Leave empty for all dates; every ad still has firstShown and lastShown.

## `dateTo` (type: `string`):

Only ads shown on or before this date, as YYYY-MM-DD (2026-06-30). Needs "Shown since". Empty means today (UTC).

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

Only ads of this format: text, image or video. Many text ads come as an image (imageUrl).

## `platform` (type: `string`):

Only ads shown on this Google platform: Search, YouTube, Shopping, Maps or Play.

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

How many ads to save for each line of "Advertisers" (1 to 5,000). Each saved ad is one $0.0012 charge, so 100 ads cost $0.12. Big advertisers have thousands of ads. The Actor reads 40 ads per request.

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

Adds, per ad, the regions where it was shown with first and last dates per region, Google's impression ranges where Google publishes them (mainly the EU), platforms and every creative variation's image. Costs one extra request and one "ad-detail" charge ($0.002) per ad, and is slower (about one ad per second). Failed lookups are free.

## `proxyConfiguration` (type: `object`):

Google rate-limits busy IP addresses, so Apify Proxy is on by default. If the run reports that Google blocked every request, pick the RESIDENTIAL proxy group and run again.

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

How many advertisers are read in parallel (1 to 3). All requests share one rate limit.

## Actor input object example

```json
{
  "advertisers": [
    "nike.com",
    "AR16735076323512287233",
    "Adidas AG"
  ],
  "region": "US",
  "dateFrom": "90 days",
  "format": "all",
  "platform": "all",
  "maxAdsPerAdvertiser": 20,
  "includeDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 2
}
```

# Actor output Schema

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

No description

## `allFields` (type: `string`):

No description

## `runReport` (type: `string`):

No description

# 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"
    ],
    "region": "US",
    "maxAdsPerAdvertiser": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("zovo-one/google-ads-transparency-scraper").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"],
    "region": "US",
    "maxAdsPerAdvertiser": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("zovo-one/google-ads-transparency-scraper").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"
  ],
  "region": "US",
  "maxAdsPerAdvertiser": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call zovo-one/google-ads-transparency-scraper --silent --output-dataset

```

## MCP server setup

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

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/4bnfvsq7N0dmvWJek/builds/Xb0n6pgO8mkiGeTO1/openapi.json
