# Google Ads Transparency Center Scraper - Reliable (`atlasdata/google-ads-transparency-scraper-reliable`) Actor

Scrape Google Ads Transparency Center (Google Ads Library): ads by domain, advertiser name, ID or URL with format, first/last shown, countries, EU impressions, images, YouTube videos. Residential proxy, auto-retries.

- **URL**: https://apify.com/atlasdata/google-ads-transparency-scraper-reliable.md
- **Developed by:** [Christian Machon](https://apify.com/atlasdata) (community)
- **Categories:** Marketing, SEO tools, Lead generation
- **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 - Reliable

**Get every Google ad an advertiser runs - by domain, advertiser name, advertiser ID or Transparency Center URL - without failed runs.** For each ad you get the advertiser, ad ID, format (text / image / video), first and last shown dates, the countries it ran in (with impression ranges in the EU), the creative image, the YouTube video for video ads, and the ad copy where Google provides it as text.

Built for **reliability**: Google answers automated traffic with "unusual traffic" blocks very quickly. This Actor uses residential IPs, rotates sessions, retries with backoff and switches connection automatically. In our last 50 test runs (2,393 ads, 25+ countries, all formats) **50 of 50 runs succeeded** and every run ended with a per-input status report. No run returned an empty dataset without saying why.

### What can you use it for?

- **Competitor ad research** - see which ads a competitor runs now and since when, in which countries and in which formats.
- **Creative inspiration and swipe files** - download ad images and YouTube video links in bulk.
- **Market entry and geo analysis** - see where a brand advertises, with EU impression ranges.
- **Agencies and brand safety** - monitor a client's or an impersonator's ads on a schedule.
- **Political and regulatory research** - collect ads from verified advertisers.
- **AI agents and automations** - clean flat JSON for Make, Zapier, n8n, LangChain or the Apify MCP server.

### Why this scraper?

| | This Actor |
|---|---|
| Blocks / "unusual traffic" | Residential IPs by default, a fresh session per block, exponential backoff, automatic fallback (residential -> datacenter -> direct, then cycling back) |
| Measured reliability | 50 / 50 test runs succeeded, from 1 ad to 400 ads per run |
| Inputs | Domain (`nike.com`), advertiser name (`Netflix`), advertiser ID (`AR...`) or any Transparency Center URL (advertiser, creative or `?domain=` search, including its `region`) |
| Filters | Region (any country), format (text / image / video), last-shown date range |
| Empty results | Never silent: every input gets a status (`SUCCEEDED`, `PARTIAL`, `NO_DATA`, `FAILED`) and a reason. When a name doesn't match an advertiser, it falls back to the matching domain (`Grammarly` -> `grammarly.com`) or lists the closest advertisers |
| Honest output | Fixed columns on every row. Fields Google doesn't provide are `null`, never guessed (see "What data you get") |
| Speed and cost | Pure HTTP, no browser, 256 MB. About 1 s per fully enriched ad, or around 400 ads in 35 s with details off |

### How to use it

1. Click **Try for free**.
2. Enter one or more **search terms**: domains, advertiser names, `AR...` IDs or Transparency Center URLs.
3. Optionally choose a **region**, **format** and **date range**.
4. Click **Start**, then download results as JSON, CSV or Excel, or fetch them via API.

### Input example

```json
{
  "searchTerms": ["nike.com", "Netflix", "AR16735076323512287233",
                  "https://adstransparency.google.com/?region=FR&domain=temu.com"],
  "region": "DE",
  "format": "ALL",
  "dateFrom": "2026-09-01",
  "maxAdsPerSearch": 100,
  "includeAdDetails": true,
  "includeCreativeContent": true
}
```

| Field | Description |
|---|---|
| `searchTerms` | Domains, advertiser names, advertiser IDs (`AR…`) or Transparency Center URLs (up to 200). Anything that looks like a domain (including `Booking.com`) is searched as a domain. |
| `region` | Country code (`US`, `DE`, …) or empty for anywhere. A `region` inside a pasted URL is used for that URL. |
| `format` | `ALL`, `TEXT`, `IMAGE` or `VIDEO`. |
| `dateFrom` / `dateTo` | Keep ads shown within this range (`YYYY-MM-DD`, inclusive). Results are newest first, so a `dateFrom` also makes runs faster. |
| `maxAdsPerSearch` | Maximum ads per search term (default 100). |
| `advertiserNameMatch` | For names: `best` (the matching advertiser with the most ads), `all` (every advertiser whose name contains the term, up to `maxAdvertisersPerName`) or `exact`. |
| `includeAdDetails` | Per-ad lookup for countries, regional dates, impressions and all variation images (default on). Turn it off for fast ad lists. |
| `includeCreativeContent` | Loads the ad preview to get YouTube video IDs and text/shopping ad copy (default on). |
| `proxyConfiguration`, `proxyFallback`, `maxRetries`, `maxConcurrency`, `failOnNoData` | Reliability controls. The defaults are good. |

### What data you get

One row per ad. These fill rates were measured over 1,883 fully enriched ads in our tests:

| Field | Filled | Notes |
|---|---|---|
| `advertiserId`, `advertiserName`, `creativeId`, `format`, `lastShown`, `adUrl`, `advertiserUrl` | 100% | `adUrl` opens the ad in the Transparency Center |
| `firstShown` | ~100% | ISO timestamp, globally |
| `regionCodes`, `regionCount`, `regions[]` | 100% (details on) | Each region has its own `firstShown`/`lastShown` dates; per-region `firstShown` is sometimes `null` |
| `targetDomain` | ~87% | Domain the advertiser is verified for/advertises |
| `imageUrl` | ~77% | Image ads, text ads archived as images, shopping product images. `imageWidth`/`imageHeight` only for archived images |
| `variationImageUrls`, `variationCount` | 57% / 100% | All image variations of the ad |
| `videoId`, `videoUrl` | ~90% of video ads | YouTube video for video ads |
| `headline` | ~24% overall | Mostly shopping product titles and some responsive search/local ads |
| `description`, `displayUrl` | ~3% | Only for the rare text ads Google stores as text |
| `impressionsMin`, `impressionsMax` | EU/EEA regions only | Google publishes impression ranges only for ads shown in the EU (DSA). `null` elsewhere |
| `searchInput`, `searchType`, `regionFilter`, `scrapedAt` | Run metadata | |

**Important, applies to every scraper:** Google archives most text (search) ads as an **image** of the ad, not as text. For those, the ad copy is visible in `imageUrl` but `headline`/`description` are `null`. We don't OCR or invent text. Dynamic keyword insertion ads may show templates such as `{Keyword:Nike sandals}` exactly as Google stores them.

### Output example

```json
{
  "searchInput": "tesla.com", "searchType": "domain", "regionFilter": "DE",
  "advertiserId": "AR17828074650563772417", "advertiserName": "Tesla Inc.",
  "creativeId": "CR18431297936794058753", "format": "VIDEO",
  "firstShown": "2026-07-13T13:27:47.000Z", "lastShown": "2026-10-26T13:19:11.000Z",
  "adUrl": "https://adstransparency.google.com/advertiser/AR17828074650563772417/creative/CR18431297936794058753?region=DE",
  "targetDomain": "tesla.com",
  "videoId": "TOnJMLfOZCs", "videoUrl": "https://www.youtube.com/watch?v=TOnJMLfOZCs",
  "headline": null, "variationCount": 3,
  "regionCount": 1, "regionCodes": ["DE"],
  "regions": [{ "regionCode": "DE", "regionName": "Germany", "firstShown": "2026-07-13", "lastShown": "2026-10-26", "impressionsMin": 15000, "impressionsMax": 20000 }],
  "impressionsMin": 15000, "impressionsMax": 20000
}
```

The Output tab has three views: **Overview**, **Creatives** and **Reach (regions and impressions)**.

#### Run summary

Each run stores a summary in the key-value store record **`OUTPUT`**. It includes per-input status, the advertisers that were matched, Google's estimated total ad count, errors, notes (for example "no advertiser named X, searched domain x.com instead"), and connection stats (requests, retries, blocks, the connection that worked). Use it in pipelines to detect partial results.

### Pricing

Pay per event, with everything included: details, video IDs, ad copy and residential proxy.

| Event | Price |
|---|---|
| Actor start | **$0.003** per run |
| Ad returned | **$0.0015** per ad (= $1.50 per 1,000 ads) |

You pay only for ads that are actually returned. There are no extra fees for details, assets or proxy. Example: 100 ads with full details costs $0.153. Set a *maximum cost per run* in the run options and the Actor stops cleanly when it is reached.

### FAQ

**Is it legal?** The Ads Transparency Center is a public Google service, and this Actor reads only what is publicly shown there. Make sure your use complies with Google's terms and the laws that apply to you.

**Why is the ad text empty for most text ads?** Google stores them as images (see above). The `imageUrl` shows the full ad.

**Why no impressions for my US ads?** Google publishes impression ranges only for EU/EEA regions.

**Can I filter by platform (Search, YouTube, Shopping, Maps)?** Not yet. Google's platform filter isn't reliable enough for us to expose honestly.

**How do date filters work?** An ad is kept if it was shown at any time within your range (its first-to-last-shown period overlaps it).

**Name search found the wrong company?** Use `advertiserNameMatch: "all"` to see every candidate, or paste the advertiser ID or URL from the Transparency Center.

**Do I need a proxy?** No. Residential proxy is used by default and included. You can supply your own proxies.

### Limits

- Up to 10,000 ads per search term (Google's own result paging applies).
- Impression ranges: EU/EEA only. Ad copy as text: only where Google stores it as text.
- No platform or political-topic filter. Google's search by advertiser name is fuzzy, so prefer domains or IDs for exact results.

# Actor input Schema

## `searchTerms` (type: `array`):

One per line. Accepted: a website domain ("nike.com" - returns ads from every advertiser account promoting that domain, best for brand/competitor monitoring), an advertiser name ("Nike, Inc." - resolved via the Transparency Center's own search), an advertiser ID ("AR16735076323512287233"), or any adstransparency.google.com URL (advertiser page, domain search or single ad). Up to 200 per run.

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

Only return ads shown in this country. Leave as "Anywhere" for all regions. A region set in a pasted URL (?region=XX) overrides this for that URL.

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

Filter by ad format (applied by Google, server-side).

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

Only ads whose last shown date is on/after this date (YYYY-MM-DD). Results come newest-first, so this also stops pagination early and saves time.

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

Only ads whose first shown date is on/before this date (YYYY-MM-DD).

## `maxAdsPerSearch` (type: `integer`):

Stop after this many ads for each search term. Big brands have 10,000+ ads.

## `advertiserNameMatch` (type: `string`):

Only used for advertiser-name inputs. Many brands run ads from several legal entities (e.g. "Nike, Inc.", "Nike Retail BV"); use a domain to catch them all.

## `maxAdvertisersPerName` (type: `integer`):

With "All matching advertisers": how many advertiser accounts to include per name.

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

Make one extra request per ad to get the list of countries it was shown in (with per-country first/last shown dates) and, for ads shown in the EU, Google's impression ranges. Disable for faster, list-only runs.

## `includeCreativeContent` (type: `boolean`):

For ads that Google renders with a preview script (all video ads and some text/shopping ads), download it to extract the YouTube video ID/URL and, where present, the headline, description and display URL. Most text ads are archived by Google as an image (imageUrl), so their copy is not available as text.

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

Google blocks IPs that send too many requests ("unusual traffic"). Apify residential proxy is the default because Google blocks shared datacenter IPs almost immediately; proxy traffic is included in the per-ad price. The Actor automatically switches connection when one gets blocked.

## `proxyFallback` (type: `boolean`):

When Google keeps blocking the current connection, switch automatically to the next one: your proxy -> Apify residential -> Apify datacenter -> direct.

## `maxRetries` (type: `integer`):

How many times a blocked or failed request is retried (with backoff and a new IP/session).

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

Parallel requests for ad details/previews. Search terms are processed 2 at a time.

## `failOnNoData` (type: `boolean`):

Mark the run as FAILED when no ads are found for any input (useful in pipelines). By default the run succeeds and the summary explains why it is empty.

## Actor input object example

```json
{
  "searchTerms": [
    "nike.com",
    "Booking.com"
  ],
  "region": "",
  "format": "ALL",
  "maxAdsPerSearch": 20,
  "advertiserNameMatch": "best",
  "maxAdvertisersPerName": 5,
  "includeAdDetails": true,
  "includeCreativeContent": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "proxyFallback": true,
  "maxRetries": 8,
  "maxConcurrency": 4,
  "failOnNoData": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `creatives` (type: `string`):

No description

## `summary` (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 = {
    "searchTerms": [
        "nike.com",
        "Booking.com"
    ],
    "maxAdsPerSearch": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("atlasdata/google-ads-transparency-scraper-reliable").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 = {
    "searchTerms": [
        "nike.com",
        "Booking.com",
    ],
    "maxAdsPerSearch": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("atlasdata/google-ads-transparency-scraper-reliable").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 '{
  "searchTerms": [
    "nike.com",
    "Booking.com"
  ],
  "maxAdsPerSearch": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call atlasdata/google-ads-transparency-scraper-reliable --silent --output-dataset

```

## MCP server setup

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

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/xz61pZahKPxFBnwid/builds/GQavUvZ3VujCYiTml/openapi.json
