# Google Ads Transparency Scraper — No Login, No Blocks (`viralanalyzer/google-ads-transparency`) Actor

Extract competitor ads from Google Ads Transparency Center (Search, YouTube, Maps, Play, Shopping). No login or API key required. Compliance + competitive intelligence.

- **URL**: https://apify.com/viralanalyzer/google-ads-transparency.md
- **Developed by:** [viralanalyzer](https://apify.com/viralanalyzer) (community)
- **Categories:** Marketing, Lead generation, Business
- **Features:** Limited permissions
- **Stats:** 5 total users, 1 monthly users, 98.6% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $2.00 / 1,000 creative scrapeds

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

> 🔗 [View on Apify Store](https://apify.com/viralanalyzer/google-ads-transparency) | 🇺🇸 English | [🇧🇷 Português](#português)

Extract competitor ad creatives from **Google Ads Transparency Center** — ads running on Google Search, YouTube, Maps, Play and Shopping. **No login or API key required.** Renders the `adstransparency.google.com` SPA with Playwright and reads the advertiser and creative cards from the live DOM.

### ✨ Features

- **Anonymous access** — no Google account, no OAuth, no API key
- **Search by advertiser name/domain** OR **direct lookup by AR... advertiser ID**
- **18 region filters** (US/BR/GB/DE/FR/ES/IT/CA/AU/MX/AR/CL/CO/JP/IN/NL/BE + Anywhere)
- **Format filter** — TEXT / IMAGE / VIDEO / ALL
- **Auto-pagination** up to 500 creatives per advertiser
- **Output per creative** — creative ID, headline, body, image URL, video URL, destination URL, and the countries the card lists under "Shown in"
- **Paced navigation** — waits of 0.5s to 4s between scrolls, advertiser pages and SPA transitions
- **NEVER 0 ITEMS guard** — fails loud if Google rotated schema instead of silent success

### 📥 Input

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `mode` | enum | Yes | `searchTerm` | `searchTerm` = find by name/domain, `advertiserId` = direct lookup |
| `searchTerm` | string | If mode=searchTerm | `Nike` | Advertiser name, brand or domain |
| `advertiserId` | string | If mode=advertiserId | — | Google advertiser ID (format `AR...`) |
| `region` | enum | No | `anywhere` | ISO country code or `anywhere` |
| `formatFilter` | enum | No | `ALL` | `TEXT` / `IMAGE` / `VIDEO` / `ALL` |
| `maxCreatives` | int | No | 50 | Max creatives per advertiser (1-500) |
| `maxAdvertisers` | int | No | 3 | Top-N matching advertisers to fetch (search mode only) |

#### Example input

```json
{
  "mode": "searchTerm",
  "searchTerm": "Nike",
  "region": "US",
  "formatFilter": "VIDEO",
  "maxCreatives": 50,
  "maxAdvertisers": 1
}
```

### 📤 Output

```json
{
  "creativeId": "CR123456789",
  "advertiserId": "AR12345678",
  "advertiserName": "Nike, Inc.",
  "advertiserDomain": "nike.com",
  "format": "VIDEO",
  "headline": "Just Do It",
  "body": "Discover the new Air Max collection…",
  "imageUrl": "https://tpc.googlesyndication.com/.../image.jpg",
  "videoUrl": "https://tpc.googlesyndication.com/.../video.mp4",
  "destinationUrl": "https://www.nike.com/...",
  "regions": [
    {"region": "US", "firstShown": null, "lastShown": null}
  ],
  "creativeUrl": "https://adstransparency.google.com/advertiser/AR12345678/creative/CR123456789",
  "source": "google-ads-transparency"
}
```

Those are all the keys — the item has no others. `regions` is built from the "Shown in XX" text the creative card renders, so `firstShown` and `lastShown` are keys of the shape and stay `null`: the grid card carries the country, not the date range. There is no impression, spend or `timesShown` metric anywhere in the item.

### ✅ Capabilities & Limits

Stated up front, so you do not pay a run to find out.

**Built here:** in `mode: "searchTerm"` the actor does not read a results page - the Transparency Center has none. It types the term into the live SPA combobox and, when no advertiser anchors appear in the DOM, clicks the first `maxAdvertisers` entries of Google's autocomplete listbox one by one (`[role="option"]`, `noWaitAfter: true` because routing is client-side React). The term has to produce Google autocomplete suggestions: brand names work, generic keywords resolve to nothing.

| Input / feature | Supported | Notes |
|---|---|---|
| `mode` — **required** | ✅ | Choose 'searchTerm' to search advertisers by name/domain, or 'advertiserId' for direct lookup if you already have the AR... ID. |
| `searchTerm` | ✅ | Advertiser name, brand or domain to search (e.g. 'Nike', 'Magalu', 'shopify.com'). Required when mode=searchTerm. |
| `advertiserId` | ✅ | Direct Google advertiser ID format AR.... Required when mode=advertiserId. Find via the Transparency Center URL. |
| `region` | ✅ | ISO-3166 country code to filter ads shown in that region. 'anywhere' = no filter. |
| `formatFilter` | ✅ | Filter by ad format. ALL = no filter. |
| Result volume (`maxCreatives`) | ⚠️ | Maximum number of ad creatives to return per advertiser (1-500). |
| Result volume (`maxAdvertisers`) | ⚠️ | When mode=searchTerm, how many top-matching advertisers to scrape ads for. |
| Proxy | ⚠️ | Proxy settings. Google Ads may block or challenge requests without proxies. |
| Impressions / times shown | ❌ | the creative grid carries no impression count. There is no `timesShown` field, and none is estimated |
| Ad spend or budget | ❌ | not extracted |
| First / last shown dates | ⚠️ | `firstShown` and `lastShown` exist inside `regions[]` and are always `null` — the card gives the country, not the date range |
| Advertiser-level totals | ❌ | one item per creative; no per-advertiser aggregate is emitted |

### 💰 Pricing

**$0.005 per creative returned** (`creative-scraped`), plus the Apify platform usage of the run,
which is billed to you at Apify's standard rates and shown on the run page.

You are charged only when a real creative comes back. A blocked run, or one where the source
answered with nothing, returns a labeled diagnostic row and charges no event.

### 🚀 Use cases

- **Competitive ad intelligence** — see what your competitors are spending on
- **Compliance research** — track political/issue ads at scale
- **Creative analysis** — extract winning headline/copy/imagery patterns
- **Brand safety** — discover ads using your brand keywords
- **Affiliate research** — find advertiser destination URLs for affiliate matching

### ⚠️ Common errors

| Error | Cause | Fix |
|---|---|---|
| `[FAIL] No advertisers resolved for "<term>"` | The term produced no Google autocomplete suggestion | Use the brand name as Google spells it, or switch to `mode: advertiserId` |
| `[FAIL] Zero items with NO anti-bot block` | The advertiser page rendered but no creative card matched | Try `region: anywhere` + `formatFilter: ALL` |
| Diagnostic item with `_dataQuality: "diagnostic"` | A block was confirmed (403 / 429 / captcha / timeout) | Re-run, ideally with residential proxies. Nothing is charged on this path |

### 🔒 No data sent to third parties

Requests go to `adstransparency.google.com` and to nothing else. Traffic is routed through Apify Proxy when `proxyConfiguration` is on, which is the default; no other middleware sees your search terms.

### 📚 Related actors

- [Facebook Ad Library Intelligence](https://apify.com/viralanalyzer/facebook-ads-library) — Meta Ad Library (FB/IG/Messenger/WhatsApp ads)

### 🆕 Changelog

- **v2.0**: Rewritten on PlaywrightCrawler — the Transparency Center is a pure SPA, so advertiser and creative cards are read from the rendered DOM. Screenshot and HTML dump saved to the Key-Value Store on failure.
- **v1.0** (2026-05-15): Initial release. Auto-pagination. NEVER 0 ITEMS guard.

***

### Português

## 📢 Google Ads Transparency Center Scraper

Extrai criativos publicitários de **competidores** do **Google Ads Transparency Center** — ads rodando em Google Search, YouTube, Maps, Play e Shopping. **Sem login, sem API key.** Renderiza a SPA do `adstransparency.google.com` com Playwright e lê os cards de anunciante e de criativo direto do DOM.

#### ✨ Funcionalidades

- **Acesso anônimo** — sem conta Google, sem OAuth, sem API key
- **Busca por nome/domínio do anunciante** OU **consulta direta pelo ID de anunciante AR...**
- **18 filtros de região** (US/BR/GB/DE/FR/ES/IT/CA/AU/MX/AR/CL/CO/JP/IN/NL/BE + Anywhere)
- **Filtro de formato** — TEXT / IMAGE / VIDEO / ALL
- **Paginação automática** até 500 criativos por anunciante
- **Saída por criativo** — ID do criativo, headline, body, URL da imagem, URL do vídeo, URL de destino e os países que o card lista em "Shown in"
- **Navegação pausada** — esperas de 0,5s a 4s entre scrolls, páginas de anunciante e transições da SPA
- **Guard NEVER 0 ITEMS** — falha de forma explícita se o Google trocar o schema, em vez de sucesso silencioso

#### 📥 Entrada

| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
| `mode` | enum | Sim | `searchTerm` | `searchTerm` = buscar por nome/domínio, `advertiserId` = consulta direta |
| `searchTerm` | string | Se mode=searchTerm | `Nike` | Nome do anunciante, marca ou domínio |
| `advertiserId` | string | Se mode=advertiserId | — | ID de anunciante do Google (formato `AR...`) |
| `region` | enum | Não | `anywhere` | Código de país ISO ou `anywhere` |
| `formatFilter` | enum | Não | `ALL` | `TEXT` / `IMAGE` / `VIDEO` / `ALL` |
| `maxCreatives` | int | Não | 50 | Máximo de criativos por anunciante (1-500) |
| `maxAdvertisers` | int | Não | 3 | Top-N anunciantes correspondentes a buscar (apenas no modo de busca) |

##### Exemplo de entrada

```json
{
  "mode": "searchTerm",
  "searchTerm": "Nike",
  "region": "US",
  "formatFilter": "VIDEO",
  "maxCreatives": 50,
  "maxAdvertisers": 1
}
```

#### 📤 Saída

```json
{
  "creativeId": "CR123456789",
  "advertiserId": "AR12345678",
  "advertiserName": "Nike, Inc.",
  "advertiserDomain": "nike.com",
  "format": "VIDEO",
  "headline": "Just Do It",
  "body": "Discover the new Air Max collection…",
  "imageUrl": "https://tpc.googlesyndication.com/.../image.jpg",
  "videoUrl": "https://tpc.googlesyndication.com/.../video.mp4",
  "destinationUrl": "https://www.nike.com/...",
  "regions": [
    {"region": "US", "firstShown": null, "lastShown": null}
  ],
  "creativeUrl": "https://adstransparency.google.com/advertiser/AR12345678/creative/CR123456789",
  "source": "google-ads-transparency"
}
```

Those are all the keys — the item has no others. `regions` is built from the "Shown in XX" text the creative card renders, so `firstShown` and `lastShown` are keys of the shape and stay `null`: the grid card carries the country, not the date range. There is no impression, spend or `timesShown` metric anywhere in the item.

#### 🚀 Casos de Uso

- **Inteligência competitiva de ads** — veja no que seus concorrentes estão gastando
- **Pesquisa de compliance** — acompanhar ads políticos/de interesse público em escala
- **Análise de criativos** — extrair padrões vencedores de headline/copy/imagem
- **Brand safety** — descobrir ads que usam as palavras-chave da sua marca
- **Pesquisa de afiliação** — encontrar URLs de destino dos anunciantes para matching de afiliação

#### ⚠️ Erros Comuns

| Erro | Causa | Correção |
|---|---|---|
| `[FAIL] No advertisers resolved for "<termo>"` | O termo não gerou sugestão no autocomplete do Google | Use o nome da marca como o Google escreve, ou troque para `mode: advertiserId` |
| `[FAIL] Zero items with NO anti-bot block` | A página do anunciante renderizou, mas nenhum card de criativo casou | Tente `region: anywhere` + `formatFilter: ALL` |
| Item de diagnóstico com `_dataQuality: "diagnostic"` | Bloqueio confirmado (403 / 429 / captcha / timeout) | Rode de novo, de preferência com proxy residencial. Nada é cobrado nesse caminho |

#### 💰 Preços

Pay-per-event: você só é cobrado quando um criativo real é retornado. Zero resultados → zero cobrança.

#### 🔒 Nenhum dado enviado a terceiros

As requisições vão para o `adstransparency.google.com` e para mais nada. O tráfego passa pelo Apify Proxy quando `proxyConfiguration` está ativo, que é o padrão; nenhum outro intermediário vê seus termos de busca.

#### 📚 Actors Relacionados

- [Facebook Ad Library Intelligence](https://apify.com/viralanalyzer/facebook-ads-library) — Meta Ad Library (ads de FB/IG/Messenger/WhatsApp)

#### 🆕 Histórico de Versões

- **v2.0**: Reescrito em PlaywrightCrawler — o Transparency Center é uma SPA pura, então os cards de anunciante e de criativo são lidos do DOM renderizado. Screenshot e dump de HTML salvos no Key-Value Store em caso de falha.
- **v1.0** (2026-05-15): Release inicial. Paginação automática. Guard NEVER 0 ITEMS.

#### Diferencial vs competidores na Apify Store

- **Sem auth**: 0 fricção de onboarding (concorrentes pedem OAuth ou são pagos)
- **Multi-region**: 18 países pré-configurados, não só US
- **PPE**: você paga só pelos criativos retornados, não por run vazio
- **Sem API paga**: lê a mesma página pública do Transparency Center, sem assinatura de terceiros

#### Casos de uso para o mercado BR/LATAM

- Espiar campanhas Google Ads de Magalu, Americanas, Mercado Livre, Magazine Luiza
- Compliance eleitoral — ads políticos no BR/AR/MX
- Pesquisa de afiliação — encontrar advertisers ativos para abordar
- Análise criativa — copiar padrões de headline/copy dos top spenders

# Actor input Schema

## `mode` (type: `string`):

Choose 'searchTerm' to search advertisers by name/domain, or 'advertiserId' for direct lookup if you already have the AR... ID.

## `searchTerm` (type: `string`):

Advertiser name, brand or domain to search (e.g. 'Nike', 'Magalu', 'shopify.com'). Required when mode=searchTerm.

## `advertiserId` (type: `string`):

Direct Google advertiser ID format AR.... Required when mode=advertiserId. Find via the Transparency Center URL.

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

ISO-3166 country code to filter ads shown in that region. 'anywhere' = no filter.

## `formatFilter` (type: `string`):

Filter by ad format. ALL = no filter.

## `maxCreatives` (type: `integer`):

Maximum number of ad creatives to return per advertiser (1-500).

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

When mode=searchTerm, how many top-matching advertisers to scrape ads for.

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

Proxy settings. Google Ads may block or challenge requests without proxies.

## Actor input object example

```json
{
  "mode": "searchTerm",
  "searchTerm": "Nike",
  "region": "US",
  "formatFilter": "ALL",
  "maxCreatives": 5,
  "maxAdvertisers": 1,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All extracted records as a dataset (JSON/CSV/Excel).

# 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 = {
    "mode": "searchTerm",
    "searchTerm": "Nike",
    "region": "US",
    "maxCreatives": 5,
    "maxAdvertisers": 1,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("viralanalyzer/google-ads-transparency").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 = {
    "mode": "searchTerm",
    "searchTerm": "Nike",
    "region": "US",
    "maxCreatives": 5,
    "maxAdvertisers": 1,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("viralanalyzer/google-ads-transparency").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 '{
  "mode": "searchTerm",
  "searchTerm": "Nike",
  "region": "US",
  "maxCreatives": 5,
  "maxAdvertisers": 1,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call viralanalyzer/google-ads-transparency --silent --output-dataset

```

## MCP server setup

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

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/9GHwDF6LNNAUW5hsP/builds/iT59TNnCx8mJqwcnn/openapi.json
