# Google Ads Transparency Scraper · Creatives & Impression Ranges (`corent1robert/google-ads-transparency-scraper`) Actor

Scrape Google Ads Transparency Center by brand, domain, advertiser ID or URL. Export Search copy, images, YouTube IDs, plus who paid, impression ranges and platforms when Google publishes them

- **URL**: https://apify.com/corent1robert/google-ads-transparency-scraper.md
- **Developed by:** [Corentin Robert](https://apify.com/corent1robert) (community)
- **Categories:** Developer tools, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 creative scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### What does Google Ads Transparency Scraper do?

This Actor scrapes the public [Google Ads Transparency Center](https://adstransparency.google.com/) and exports **one row per creative**. Paste a **brand name**, **domain**, **advertiser ID** (`AR…`), or a Transparency URL.

Two audiences, one run:

- **Creative / swipe file** — Search headlines, images, YouTube IDs, first / last shown.
- **Media buyer / adtech** — legal entity (`paidForBy`), impression ranges, countries, Search vs Display — **when Google publishes them**.

It is a **Google Ads Transparency API alternative** — Google does not offer an official API for this data. It does **not** read Google Ads Manager. You will not get spend, CPC, CTR, or private keywords.

### Why scrape the Google Ads Transparency Center?

Marketers use the Transparency Center to see which ads a competitor is running on Google Search, YouTube, and Display. Doing that by hand does not scale. Same job on Meta: [Facebook Ads Library Scraper](https://apify.com/corent1robert/facebook-ads-library-scraper).

- Compare creative strategy across brands
- Pull Search headlines into a teardown spreadsheet
- Collect YouTube ad IDs for a swipe file
- See **who paid** and **how many impressions** Google discloses (ranges, not Ads Manager stats)
- Monitor when creatives first and last appeared

On Apify you can **schedule** runs, download **JSON / CSV / Excel**, and call the Actor from the **API** or integrations (Sheets, Make, n8n).

### What data can Google Ads Transparency Scraper extract?

| Field | Description |
|---|---|
| `headline`, `description` | Search ad copy when Google publishes the TEXT bundle |
| `displayUrl`, `businessName` | Visible URL and business name on TEXT ads |
| `imageUrl`, `imageUrls` | Creative image(s) (PNG/JPEG archive) |
| `youtubeVideoId`, `thumbnailUrl` | YouTube ID and thumbnail when the VIDEO preview exposes them (~half of video ads) |
| `format` | `TEXT`, `IMAGE`, `VIDEO`, or `UNKNOWN` |
| `firstShownAt`, `lastShownAt` | Run dates (ISO UTC) |
| `advertiserName`, `advertiserId`, `advertiserUrl`, `creativeUrl` | Advertiser identity and Transparency links |
| `paidForBy` | Legal entity Google shows as paying for the ad |
| `impressionsAvailable` | `true` when Google published an impression range |
| `impressionsLower`, `impressionsUpper` | Public impression range (not Ads Manager). Lower may be null (UI “< N”) |
| `impressionsByRegion`, `platformNames` | Country split and surfaces (Search / Display / Maps, inferred) |
| `targeting` | Include/exclude flags for the targeting *methods* Google discloses |

Not extracted (and not invented): spend, budget, CPC, CTR, conversions, Ads Manager keywords, emails. Impression counts and targeting method flags are public Transparency fields — they stay **null** when Google does not publish them for that creative.

### How to scrape competitor Google ads

1. Open this Actor in Apify Console.
2. In **Query**, paste a brand (`Qonto`), a domain (`qonto.com`), an advertiser ID (`AR…`), or a Transparency Center URL.
3. Keep **Region** on Anywhere unless you only care about one country.
4. Leave **Max ads** at 20 for a first run, then raise it.
5. Keep **Include who paid & impression ranges** on unless you only want a swipe file.
6. Click **Start**. Download the dataset as JSON, CSV, or Excel. Use the **Creatives — Media buyer** view for impression columns.

See the **Input** tab for the visible options (Residential proxy is automatic — not in the form).

### How much will it cost to scrape Google ads?

This Actor uses **pay-per-event** pricing. You only pay per **creative written to the dataset**. Compute and Residential proxy are included — there is **no Actor-start fee**. Paid Apify plans get a lower price per creative.

| Apify plan | Per creative | Per 1,000 |
|---|---|---|
| Free | **$0.003** | **$3.00** |
| Bronze | **$0.0027** | **$2.70** |
| Silver | **$0.0024** | **$2.40** |
| Gold | **$0.0021** | **$2.10** |
| Platinum | **$0.0018** | **$1.80** |
| Diamond | **$0.0015** | **$1.50** |

| Run (Free plan) | Approx. cost |
|---|---|
| Default (20 ads) | **$0.06** |
| 100 ads | **$0.30** |
| 1,000 ads | **$3.00** |

Set **Max ads** and, on Apify, a **max total charge** so a run cannot exceed your budget. A row with empty `headline` / `youtubeVideoId` / impressions still counts — Google did not publish those fields; the creative was still scraped.

Default memory is **512 MB** (HTTP only, no browser).

### Input

Visible Console fields:

| Field | Default | Notes |
|---|---|---|
| `query` | `Qonto` | Name, domain, `AR…`, or Transparency URL |
| `region` | `anywhere` | `?region=` on a pasted URL overrides this |
| `adFormats` | All | Text / Image / Video |
| `dateRange` | Any time | Filter on last-shown date (client-side) |
| `maxAdvertisers` | 3 | Name/domain search only |
| `maxAds` | 20 | **Global** cap for the run (`0` = unlimited) |
| `enrichMediaBuyerData` | `true` | **Include who paid & impression ranges.** Off = swipe file only. |
| `platforms` | All | Optional Search / Display / Maps filter (forces the lookup above) |

Residential **Apify Proxy** is always on (hidden). A creative ID (`CR…`) alone is not enough — paste the full Transparency creative URL. Ads Manager URLs (`ads.google.com`) are rejected.

Example:

```json
{
  "query": "Qonto",
  "region": "anywhere",
  "maxAds": 20
}
```

### Output

You can download the dataset in JSON, HTML, CSV, or Excel.

```json
{
  "advertiserName": "Qonto SA",
  "advertiserId": "AR05318151651209510913",
  "creativeId": "CR01362885945854001153",
  "format": "TEXT",
  "headline": "Qonto, le compte pro en ligne",
  "description": "Gérez toutes vos dépenses pro et optimisez votre trésorerie.",
  "displayUrl": "www.qonto.com",
  "imageUrl": "https://tpc.googlesyndication.com/archive/simgad/…",
  "youtubeVideoId": null,
  "paidForBy": "OLINDA SAS",
  "impressionsAvailable": true,
  "impressionsLower": null,
  "impressionsUpper": 1000,
  "platformNames": "SEARCH, DISPLAY",
  "firstShownAt": "2025-05-15T13:36:30.000Z",
  "lastShownAt": "2026-07-28T13:02:38.000Z",
  "region": "anywhere",
  "creativeUrl": "https://adstransparency.google.com/advertiser/AR05318151651209510913/creative/CR01362885945854001153?region=anywhere"
}
```

Console views: **Creatives — Overview**, **Creatives — Copy & media** (swipe file), **Creatives — Media buyer** (who paid / impressions).

### Related Actors

These Actors cover the same job or the next step in the workflow. Apify’s automatic recommendations stay inside one category — this list is the rest of the toolkit.

| Actor | Use it when |
|---|---|
| [Instagram Sponsored Feed Scraper](https://apify.com/corent1robert/instagram-sponsored-feed-scraper) | Sponsored posts in the Instagram feed |
| [Facebook Ads Library Scraper · Meta Page Ads, Creatives & Reach](https://apify.com/corent1robert/facebook-ads-library-scraper) | Meta Ads Library — page ads, creatives and reach |
| [Facebook Page Scraper · Extract Email, Phone & Website](https://apify.com/corent1robert/facebook-page-contact-scraper) | Email, phone and website from a Facebook Page |
| [Shopify App Store Developer Contacts · Emails & Address](https://apify.com/corent1robert/shopify-app-developer-contacts) | Shopify App Store partner emails — unique publishers, not per app |
| [SW Website Rankings Scraper](https://apify.com/corent1robert/similarweb-scraper) | Rank the website / domain after you have the URL |
| [Google Maps search — place details & contacts](https://apify.com/corent1robert/google-maps-search-scraper) | Google Maps places, details and contacts |
| [French Companies · Search & SIREN Enrich](https://apify.com/corent1robert/recherche-entreprises-scraper) | French companies: search and SIREN enrich |

### FAQ, disclaimers, and support

#### Why is Residential proxy always on?

The Transparency Center returns a Google captcha (`sorry`) on datacenter or bare IPs. The Actor **always** uses Apify Proxy group **RESIDENTIAL** (hidden in Console). The run fails immediately if that proxy cannot start.

#### Why is the headline empty on some TEXT ads?

Google sometimes publishes Search ads as a **screenshot** (`simgad`) without the HTML text bundle. Those rows stay `TEXT` with `imageUrl` set and `headline` null. That is expected — not a failed scrape.

#### Why are some YouTube IDs empty?

Google does not always embed a YouTube ID in the public VIDEO preview. Empty `youtubeVideoId` is expected for a large share of video ads — not a failed scrape.

#### Do I pay for rows with empty headlines or YouTube IDs?

Yes. Pricing is **per creative scraped**, not per filled field. Empty copy / video IDs / impressions mean Google did not publish them on the Transparency Center — not that the scrape failed.

#### Why are impressions empty on some rows?

Google only publishes impression ranges for some creatives and regions (often EU Transparency / DSA). `impressionsAvailable: false` is expected — not a failed scrape. Spend and exact impression counts from Ads Manager are never available here.

#### Can I export unique advertisers instead of every ad?

Yes. Set **What to export** to **Unique advertisers**. You get one row per AR… with `paidForBy` when Google publishes it. There is **no advertiser sitemap** — start from a brand, domain, or advertiser ID, like a targeted run of [Apify Creator Scraper](https://apify.com/corent1robert/apify-users-sitemap-scraper) rather than a full dump.

#### How are Search / Display / Maps assigned?

Surface names are inferred from Transparency `GetCreativeById` ids (3 = Search, 5 = Display, 4 = Maps) using Qonto dumps. The numeric `platforms[].id` is always kept. Treat labels as best-effort.

#### Why can a name match several advertisers?

Search uses Google’s autocomplete. The Actor takes the first **Max advertisers** suggestions in Google’s order. It does not guess which “Qonto” is the one you meant. Use an `AR…` ID or Transparency URL for a precise advertiser.

#### Does region filtering always match the website?

The Actor sends the known geo id for the selected country. Google sometimes ignores geo on the creatives list. Each row still has a `region` label. Do not treat it as a 100% server-side guarantee.

Our Actors are ethical and do not extract private user data such as personal emails. They only extract what Google has chosen to publish on the Ads Transparency Center (creatives, public impression ranges, and country splits). We therefore believe that our Actors, when used for ethical purposes by Apify users, are safe. However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you are unsure whether your reason is legitimate, consult your lawyers.

Use the **Issues** tab for bugs and feature requests. Use the **API** tab to run the Actor programmatically.

# Actor input Schema

## `query` (type: `string`):

**Brand** (`Qonto`), **domain** (`qonto.com`), **advertiser ID** (`AR…`), or a full Transparency **advertiser / creative URL** (`adstransparency.google.com/…`).

Ads Manager URLs (`ads.google.com`) are rejected. A creative ID (`CR…`) alone is not enough — paste the full Transparency URL.

## `outputMode` (type: `string`):

**Creatives (default):** one row per ad (swipe file + who paid when Google publishes it).

**Unique advertisers:** one row per advertiser — legal `paidForBy`, Transparency URL, sample creative. Same idea as Shopify / Play unique publishers. Google does **not** publish an advertiser sitemap; you still start from a brand / domain / AR… query.

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

Transparency region. **Anywhere** is worldwide. A `?region=` value on a pasted Transparency URL overrides this field.

## `adFormats` (type: `array`):

Which creative formats to keep. If **All formats** is selected, other values are ignored.

## `dateRange` (type: `string`):

Keep creatives whose **last shown** date falls in this window. Applied client-side. Creatives with a missing last-shown date are kept.

## `maxAdvertisers` (type: `integer`):

When resolving a **name or domain**, how many advertisers to scrape (Google suggestion order). Ignored for a direct advertiser ID or URL. In **Unique advertisers** mode this is how many leads you try (still capped by Max ads).

## `maxAds` (type: `integer`):

**Global** cap for the whole run (all advertisers combined). **0** = unlimited. Counted after format and date filters. Default **20** keeps first runs cheap.

## `enrichMediaBuyerData` (type: `boolean`):

**On (default):** each row adds `paidForBy`, impression ranges, countries, and Search / Display / Maps **when Google publishes them**. Empty fields mean Google did not expose the data — not a failed scrape.

**Off:** swipe file only (slightly fewer requests).

## `platforms` (type: `array`):

Keep creatives that ran on these surfaces. **All** = no extra filter. Uses the lookup above (forced on if you filter). Surface names are inferred — treat as best-effort.

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

Forced to Apify Proxy RESIDENTIAL. Hidden in Console — the Transparency Center captchas other IPs.

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

Parallel HTTP requests for creative enrichment. Keep low to avoid captchas.

## `minDelayMs` (type: `integer`):

Minimum pause between every HTTP request (RPC and enrichment).

## `maxRequestRetries` (type: `integer`):

Retries on 429, captcha, or 5xx. Each retry rotates the proxy session.

## Actor input object example

```json
{
  "query": "Qonto",
  "outputMode": "creatives",
  "region": "anywhere",
  "adFormats": [
    "ALL"
  ],
  "dateRange": "ANY",
  "maxAdvertisers": 3,
  "maxAds": 20,
  "enrichMediaBuyerData": true,
  "platforms": [
    "ALL"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxConcurrency": 2,
  "minDelayMs": 800,
  "maxRequestRetries": 5
}
```

# Actor output Schema

## `overview` (type: `string`):

Image, headline, advertiser, format, dates

## `copyMedia` (type: `string`):

Search copy, images, YouTube IDs (swipe file)

## `mediaBuyer` (type: `string`):

Who paid, impression ranges, platforms

## `dataset` (type: `string`):

All creative rows

## `output` (type: `string`):

Advertisers resolved, creatives scraped, query type, media-buyer flag

## `runLog` (type: `string`):

Live progress

# 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 = {
    "query": "Qonto"
};

// Run the Actor and wait for it to finish
const run = await client.actor("corent1robert/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 = { "query": "Qonto" }

# Run the Actor and wait for it to finish
run = client.actor("corent1robert/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 '{
  "query": "Qonto"
}' |
apify call corent1robert/google-ads-transparency-scraper --silent --output-dataset

```

## MCP server setup

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