# Google Ads Transparency Scraper (`fetchfoundry-labs/google-ads-transparency-scraper`) Actor

Every Google ad an advertiser or website runs, from the Ads Transparency Center: ad text, images, YouTube video ids, first/last shown dates, regions, EU impressions, who paid and topic. Search by advertiser name, id or domain; filter by country, format and dates; monitor new ads.

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

## Pricing

from $1.05 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Google Ads Transparency Scraper — Competitor Ads, Ad Text, Images & Videos

Get every Google ad an advertiser or website runs from Google's
[Ads Transparency Center](https://adstransparency.google.com): **the actual ad
text**, images, YouTube video links, first and last shown dates, the countries
where each ad ran, EU impression ranges, who paid for it and its topic.

- Search by **advertiser name**, advertiser id or Transparency Center URL, or
  by **website domain**.
- Filter by **country shown**, **format** (image, text, video) and **date
  range**.
- **Monitor competitors**: with `onlyNewAds`, a scheduled run returns only ads
  you have not seen before.

One row per ad creative. Name matching, totals and anything that went wrong
are in a separate run report, so the dataset stays clean.

### Quick start

```json
{
  "advertisers": ["Nike, Inc."],
  "domains": ["nike.com"],
  "region": "US",
  "maxAdsPerTarget": 200
}
```

On 2026-10-10, 1,004 ads with full details and ad text took 5½ minutes in one
run.

### Output

Each row is one ad creative. Below is a real row (a shopping ad shown 9–10
million times in Poland), with long preview URLs shortened:

```json
{
  "creativeId": "CR16502104412475359233",
  "advertiserId": "AR18378488041124659201",
  "advertiserName": "Nike Retail BV",
  "format": "TEXT",
  "adType": "PRODUCT_LISTING_AD",
  "firstShown": "2021-10-25T07:00:00+00:00",
  "lastShown": "2026-10-10T09:32:17+00:00",
  "daysShown": 1772,
  "domain": null,
  "imageUrl": null,
  "previewUrl": "https://displayads-formats.googleusercontent.com/ads/preview/content.js?client=ads-integrity-transparency&...",
  "videoId": null,
  "videoUrl": null,
  "adText": "Plecak Jordan Paris Saint-Germain (27 l) - Czerń - Rozmiar: JEDEN | Nike Oficjalny",
  "adTextLines": [
    "Plecak Jordan Paris Saint-Germain (27 l) - Czerń - Rozmiar: JEDEN",
    "Nike Oficjalny"
  ],
  "creativeUrl": "https://adstransparency.google.com/advertiser/AR18378488041124659201/creative/CR16502104412475359233",
  "advertiserUrl": "https://adstransparency.google.com/advertiser/AR18378488041124659201",
  "variationCount": 2,
  "paidBy": "Nike Retail BV",
  "topic": "Luggage & Bags",
  "regions": [
    {"regionCode": "DE", "regionName": "Germany", "geoId": 2276, "firstShown": "2023-03-03",
     "lastShown": "2024-04-11", "impressionsMin": null, "impressionsMax": 1000},
    {"regionCode": "PL", "regionName": "Poland", "geoId": 2616, "firstShown": "2023-03-01",
     "lastShown": "2026-10-10", "impressionsMin": 9000000, "impressionsMax": 10000000}
  ],
  "regionCount": 6,
  "impressionsMin": 9000000,
  "impressionsMax": 10000000,
  "impressionsNote": "EU/EEA only (Digital Services Act)",
  "detailFetched": true,
  "previewFetched": true,
  "dataComplete": true,
  "_input": "advertiser:AR18378488041124659201 [AR18378488041124659201]",
  "_source": "google-ads-transparency",
  "_scrapedAt": "2026-10-10T13:50:11.726792+00:00"
}
```

The run's key-value store also has **`RUN_REPORT`**, which shows:

- which advertiser each name was matched to, and the other candidates;
- the totals Google lists for each advertiser or domain;
- why each one stopped;
- errors, requests and retries;
- whether the run switched to Residential proxy (see *Reliability and cost*).

### Field reference

**Ad identity**

| Field | Meaning |
|---|---|
| `creativeId`, `advertiserId`, `advertiserName` | Google's creative id (CR…), advertiser id (AR…) and the verified advertiser name. |
| `creativeUrl`, `advertiserUrl` | The ad's and the advertiser's pages in the Transparency Center. |
| `domain` | The website the ad points to, when Google lists one. |

**Format and type**

| Field | Meaning |
|---|---|
| `format` | Google's format: `IMAGE`, `TEXT` or `VIDEO`. |
| `adType` | What the preview actually is (see the table below). Falls back to `format` when there is no preview. |

| `adType` | What it is |
|---|---|
| `SINGLE_AD` | Search text ad: headline, display URL and description. |
| `PRODUCT_LISTING_AD` | Shopping ad: product title and store. |
| `LOCAL_AD` | Maps / local ad: business name, address and description. |
| `ADS_IN_AIX` | Ad shown in Google's AI experiences. This is Google's own name for it. |
| `IMAGE` | Image ad. |
| `VIDEO` | Video ad. |

**Dates**

| Field | Meaning |
|---|---|
| `firstShown`, `lastShown` | When the ad was first and last shown anywhere (UTC). |
| `daysShown` | Number of days the ad ran. |

**Content**

| Field | Meaning |
|---|---|
| `adText`, `adTextLines` | The visible text of the ad, read from its preview. Template slots such as "\[Price]" and "<Distance>" are removed. |
| `imageUrl`, `imageWidth`, `imageHeight` | The image of image ads, with its size. |
| `videoId`, `videoUrl` | The YouTube video of video ads. |
| `previewUrl` | Google's preview script for the ad. |
| `variationCount`, `variationImageUrls`, `variationPreviewUrls` | Other versions of the same creative (sizes, texts). |

**Who and where**

| Field | Meaning |
|---|---|
| `paidBy` | Who paid for the ad. Can differ from the advertiser (for example, a media agency). |
| `topic` | Google's topic for the ad, in English. |
| `regions` | Every country where the ad was shown: ISO code, name, first and last shown date, and impressions where published. |
| `regionCount` | Number of countries. |

**Impressions**

| Field | Meaning |
|---|---|
| `impressionsMin`, `impressionsMax`, `impressionsNote` | Total impressions range. Google publishes impressions only for EU/EEA countries (Digital Services Act). |

An impression range can be open on one side:

- Only a maximum (for example 1,000) means "under 1,000".
- Only a minimum (for example 10,000,000) means "10 million or more".

**Run bookkeeping**

| Field | Meaning |
|---|---|
| `detailFetched`, `previewFetched` | Whether the details and the preview were read. If one failed, `detailError` or `previewError` says why. |
| `dataComplete` | `true` when everything you asked for was collected for this ad. |
| `_input` | Which advertiser or domain found this ad. |
| `_source`, `_scrapedAt` | Data source and scrape time (UTC). |

### Input

| Field | Notes |
|---|---|
| `advertisers` | Names, AR ids or Transparency Center URLs. A name is matched exactly first, ignoring case and "Inc." / "LLC" / "B.V."-style suffixes; every exact match is included. With no exact match, the similar name with the most ads is used. `RUN_REPORT.advertiserResolution` lists the candidates; use an AR id when you need one specific account. |
| `domains` | Website domains. URLs are fine; they are reduced to the domain. |
| `region` | 2-letter country code where the ads were shown. Empty means anywhere. |
| `format` | `ALL`, `IMAGE`, `TEXT` or `VIDEO`. `TEXT` also covers shopping and local ads. |
| `dateFrom`, `dateTo` | YYYY-MM-DD. If you set only one, the other is filled in, because Google ignores half a range. |
| `maxAdsPerTarget` | Default 200; 0 = all. Big brands run thousands of creatives (Nike, Inc.: 8,000–9,000). |
| `includeAdDetails` | Default on: regions, impressions, who paid, topic, variations. Costs one extra request per ad. |
| `includeAdText` | Default on: ad text and YouTube id. Costs one extra request per text or video ad. |
| `onlyNewAds`, `historyStoreName` | Skip ads that earlier runs already delivered, for scheduled monitoring. |
| `residentialFallback` | Default on. See *Reliability and cost*. |
| `proxyConfiguration` | Apify datacenter proxy by default. |

### Things Google does not tell you (and how this Actor handles them)

- **Totals are ranges, not counts.** Google shows "8000–9000". They appear as
  `totalAdsMin` / `totalAdsMax` in the report.
- **Half a date range is silently ignored.** With only a start date, Google
  returns every ad. The Actor always sends both ends.
- **Topic names come back in random languages** (Spanish, Arabic, Chinese)
  unless English is requested explicitly. The Actor requests English.
- **Region-only searches return nothing.** Google needs an advertiser or a
  domain, so the Actor asks for one.
- **One brand, many advertiser accounts.** "Nike" is Nike, Inc., Nike Retail BV,
  NIKE GLOBAL TRADING B.V. and more. The report lists the candidates for each
  name, and a domain search covers all of them.

### Reliability and cost

You pay per ad row. Platform usage is small but depends on whether Google
throttles Apify's shared datacenter IPs. Both cases were measured on
2026-10-10:

| Situation | Platform usage per 1,000 ads |
|---|---|
| Datacenter proxy not throttled | ≈ $0.03 (1,004 ads in 336 s) |
| Google throttling datacenter IPs; run switched to Residential | ≈ $0.35–0.46 (204 ads in 229 s for $0.093) |

Google rate-limits busy IPs with HTTP 429. Within one hour, the same
datacenter pool went from 0 throttled requests to every request throttled.
To handle this:

- The Actor paces its requests.
- With `residentialFallback` on, after 3 throttled datacenter requests the rest
  of the run moves to Apify Residential.
- `RUN_REPORT` shows the retries by endpoint and route
  (`switchedToResidentialAfterRequests`).

Without a proxy, a test run lost one target completely to rate limiting, so
keep the default proxy on.

A run that reaches its timeout still delivers every ad collected so far,
because rows are saved page by page.

### Limits

- Data covers what Google publishes in the Transparency Center. Spend,
  targeting audiences and click data are not public.
- Impressions exist only for EU/EEA countries.
- The ad text is read from Google's preview of the ad. Ads whose preview is a
  picture only (image ads) have `imageUrl` but no `adText`.

# Actor input Schema

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

Advertiser names (e.g. "Nike, Inc."), advertiser ids (AR...) or Transparency Center advertiser URLs. A name is matched exactly first; otherwise the closest name with the most ads is used -- RUN_REPORT shows which advertiser was picked and the alternatives.

## `domains` (type: `array`):

Website domains (e.g. nike.com): every advertiser whose ads point to this domain.

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

2-letter country code where the ads were shown (US, GB, DE, ID ...). Empty = anywhere.

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

Google's format filter. TEXT also covers shopping and Maps ads; the adType column tells them apart.

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

YYYY-MM-DD. Ads shown on or after this date. If you set only one end, the other is filled in (Google ignores half a range).

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

YYYY-MM-DD. Ads shown on or before this date.

## `maxAdsPerTarget` (type: `integer`):

0 = all. Big brands run thousands of creatives (Nike, Inc.: 8,000-9,000).

## `includeAdDetails` (type: `boolean`):

Variations, regions shown with first/last dates, EU impressions ranges, who paid, and topic. One extra request per ad.

## `includeAdText` (type: `boolean`):

Read the ad preview: headline/description text of text, shopping and local ads, and the YouTube video id of video ads. One extra request per text/video ad.

## `onlyNewAds` (type: `boolean`):

Skip creatives delivered by earlier runs (remembered in a key-value store on your account). Schedule it to monitor competitors.

## `historyStoreName` (type: `string`):

Named key-value store used by 'Only new ads'.

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

Requests in flight at once.

## `residentialFallback` (type: `boolean`):

When Google rate-limits a request twice on the datacenter proxy (HTTP 429), retry it through Apify Residential. Only throttled requests use it; RUN_REPORT counts them (residentialEscalations).

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

Apify datacenter proxy (default) rotates IPs and avoids Google's rate limit: in testing it gave 0 retries where no proxy got HTTP 429 on a quarter of requests. Residential works too but is slower and costs more bandwidth.

## Actor input object example

```json
{
  "advertisers": [
    "Nike, Inc."
  ],
  "domains": [],
  "region": "",
  "format": "ALL",
  "maxAdsPerTarget": 20,
  "includeAdDetails": true,
  "includeAdText": true,
  "onlyNewAds": false,
  "historyStoreName": "google-ads-transparency-seen",
  "maxConcurrency": 4,
  "residentialFallback": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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, Inc."
    ],
    "maxAdsPerTarget": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetchfoundry-labs/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, Inc."],
    "maxAdsPerTarget": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fetchfoundry-labs/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/ZYWzcRaJwfydIiLoa/builds/QpQFuxhebmhUdp2iA/openapi.json
