# Google Ads Transparency Scraper (`elhadj.hamlaoui/ads-transparency-scraper`) Actor

Scrape every ad a brand runs on Google - just type a brand name or domain, no advertiser ID needed. Creatives, video and image previews, formats, dates and per-country breakdown. Free advertiser lookup. Pay only per ad returned.

- **URL**: https://apify.com/elhadj.hamlaoui/ads-transparency-scraper.md
- **Developed by:** [Jamel HAMLAOUI](https://apify.com/elhadj.hamlaoui) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 ad scrapeds

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 Scraper

Scrape every ad a brand runs on Google, straight from the
[Google Ads Transparency Center](https://adstransparency.google.com).

**Just type a brand name or a domain.** No advertiser IDs to hunt down, no login.

Get ad creatives, image and video previews, formats, how long each ad has been
running, and which of your target countries served it — as JSON, CSV or Excel.

### Why this one

- **Search by brand or domain** — type `Nike` or `nike.com` and go
- **Free advertiser lookup** — find every advertiser behind a brand without
  being charged a cent
- **Per-country breakdown** — ask for several countries and each ad tells you
  which ones served it, at no extra cost
- **Landing pages** — see where each ad actually sends people, free
- **No start fee** — you pay per ad returned, and nothing at all for a run that
  returns nothing
- **Fast** — about 150 ads per second
- **249 countries** supported with ordinary ISO codes (`FR`, `US`, `GB`…)

### Quick start

```json
{
  "queries": ["nike.com"],
  "maxAdsPerTarget": 100
}
```

That's it. To narrow it down:

```json
{
  "queries": ["Nike", "adidas.com"],
  "adFormat": "VIDEO",
  "regions": ["FR", "DE"],
  "shownAfter": "2026-01-01",
  "maxAdsPerTarget": 500
}
```

### Input

| Field | What it does |
|---|---|
| `queries` | Brand names or domains — `Nike`, `nike.com` |
| `advertiserIds` | Optional exact advertiser IDs (`AR…`) or full URLs |
| `searchMode` | `ads` (default) or `advertisers` for a **free** lookup |
| `adFormat` | `ALL`, `IMAGE`, `TEXT` or `VIDEO` |
| `regions` | Country codes, e.g. `["FR","US"]`. Empty = worldwide. List several and each ad reports which ones served it |
| `shownAfter` / `shownBefore` | Date window, `YYYY-MM-DD` |
| `platforms` | `YOUTUBE`, `PLAY`, or a raw numeric platform code |
| `includeCreativeDetails` | Adds landing page, display domain, size and on-creative text. Slower, **not charged extra** |
| `maxAdsPerTarget` | `0` for everything. Big brands have 20,000+ ads |

#### Free advertiser lookup

Not sure which advertiser you want? Ask first — it costs nothing:

```json
{ "queries": ["decathlon"], "searchMode": "advertisers" }
```

```json
{ "kind": "advertiser", "advertiserName": "DECATHLON FRANCE",
  "advertiserId": "AR12956355609636110337", "country": "FR",
  "verified": true, "approxAdsMin": 6, "approxAdsMax": 6 }
```

### Output

| Field | Description |
|---|---|
| `advertiserId` | Google advertiser ID |
| `advertiserName` | Verified legal name of the advertiser |
| `adId` | Creative ID |
| `format` / `formatCode` | `IMAGE`, `TEXT` or `VIDEO` |
| `firstShown` / `lastShown` | Unix timestamps |
| `daysShown` | How long the ad has been running |
| `previewUrl` | Direct link to the creative image or preview |
| `adUrl` | Link to the ad on Ads Transparency Center |
| `matchedBy` | Which query or advertiser produced this row |
| `regions` \* | Which of your selected countries served this ad |
| `destinationUrl` \*\* | Where the ad sends people |
| `adServerUrl` \*\* | Feed vendor that built the creative (Criteo, Yteo…) |
| `displayDomain` \*\* | Domain shown on the creative |
| `creativeSize` / `width` / `height` \*\* | Creative dimensions |
| `creativeText` \*\* | Text found on the creative |

\* only when you ask for specific countries
\*\* only with `includeCreativeDetails`

**How often do the starred fields fill?** It depends on the kind of ad the
brand runs, so here are two real measurements, 120 ads each:

| Brand | Size | Display domain | Creative text | Any URL |
|---|---|---|---|---|
| decathlon.fr (feed/shopping ads) | 83% | 81% | 37% | 36% |
| nike.com (mostly plain images) | 20% | 12% | 20% | 3% |

Plain image ads carry no data bundle at all, so they return nothing extra.
That is a property of the advertiser, not a fault in the scraper. We publish
these numbers rather than implying every ad is fully enriched.

Landing pages are split honestly: `destinationUrl` is the advertiser's own link
when it is present in the creative, and `adServerUrl` is the feed vendor that
assembled the ad. Many shopping ads only contain the vendor's URL, and calling
that the landing page would be wrong.

```json
{
  "advertiserId": "AR01614014350098432001",
  "advertiserName": "lululemon athletica canada inc.",
  "adId": "CR12967419969376616449",
  "format": "IMAGE",
  "firstShown": 1772749674,
  "lastShown": 1789916412,
  "daysShown": 200,
  "regions": ["FR", "US"],
  "previewUrl": "https://tpc.googlesyndication.com/archive/simgad/5316596228252826860",
  "adUrl": "https://adstransparency.google.com/advertiser/AR01614014350098432001/creative/CR12967419969376616449",
  "matchedBy": "lululemon.com"
}
```

### What you can do with it

- **Spy on competitor ads** — every creative a rival is running right now
- **Find their winners** — `daysShown` shows which creatives survive for years
- **Track launches** — new `firstShown` dates reveal fresh campaigns
- **Compare by country** — see which markets get which creatives
- **Creative research** — pull thousands of real ad images
- **Agency reporting** — show clients what their competitors advertise

### Pricing

Pay per ad returned. Runs that return nothing cost nothing, duplicates are
removed before billing, advertiser lookups are free, and the per-country
breakdown carries no surcharge.

### Proxy

Google rate-limits a single IP after roughly 60-80 requests (~2,500 ads) and
then serves a block page. Backing off does not clear it - only a different IP
does - so this Actor rotates to a fresh IP mid-run when it gets blocked, and
keeps everything it had already collected instead of failing the whole job.
Apify Proxy is on by default. Turn it off only for small test runs.

### FAQ

**Is this legal?**
It collects only what Google publishes publicly to anyone, with no login.
Ads are commercial content advertisers chose to run. **No personal data.**

**Do I need an advertiser ID?**
No. Type the brand name or domain. IDs still work if you have them.

**Why don't you return ad headline and body text?**
Google does not expose ad copy through the public data source — it only ships a
rendered creative. Rather than return empty columns, we give you the creative
preview so you can see the real ad. An honest limitation, not an oversight.

**Why is `creativeText` not called "headline"?**
Because Google does not label it. The text is recovered from the creative's
own render bundle, and its order there is not the order a viewer sees. Calling
it a headline would be a guess, so we hand you the text and let you judge.

**How does the per-country breakdown work?**
Google's per-ad country endpoint requires a signed-in Google session, which a
scraper cannot have. So when you list several countries we search each one and
report which of them actually served each ad. Real data, public endpoint only.

**Which platform codes work?**
`YOUTUBE` and `PLAY` are verified against Google's own interface. The remaining
codes get clamped rather than filtered, so Search / Shopping / Maps cannot be
told apart reliably - we let you pass raw numbers rather than ship labels we
have not proven.

**What if the output breaks?**
Google can change this source without warning. An automated contract test
catches shape changes. Report an issue and it will be fixed.

# Actor input Schema

## `queries` (type: `array`):

Search by brand name (e.g. "Nike") or domain (e.g. "nike.com"). No advertiser ID needed.

## `advertiserIds` (type: `array`):

Optional. Exact advertiser IDs (AR...) or full Ads Transparency URLs, if you already know them.

## `searchMode` (type: `string`):

"ads" scrapes the ad creatives. "advertisers" just lists the advertisers and domains matching your query - this is FREE and costs nothing.

## `adFormat` (type: `string`):

Return only one creative format, or all of them.

## `regions` (type: `array`):

Only ads shown in these countries. Use ISO codes like FR, US, GB, DE. Listing more than one also tells you WHICH of them served each ad, in the `regions` output field. Leave empty for worldwide.

## `shownAfter` (type: `string`):

Only ads still running on or after this date (YYYY-MM-DD).

## `shownBefore` (type: `string`):

Only ads that started on or before this date (YYYY-MM-DD).

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

Filter by where the ad ran. "YOUTUBE" and "PLAY" are verified against Google's own interface. Other Google platforms can be targeted with their raw numeric code if you know it - we don't guess at labels we haven't proven.

## `includeCreativeDetails` (type: `boolean`):

Adds the landing page URL, display domain, creative size and on-creative text by reading each ad's creative bundle. One extra request per ad so it is slower, and NOT every ad carries this data - but you are not charged extra for it.

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

Stop after this many ads per brand/domain/advertiser. 0 = no limit. Big brands have 20,000+ ads, so set a cap unless you want everything.

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

Google rate-limits single IP addresses quickly. Keep the proxy enabled for anything beyond a few hundred ads.

## Actor input object example

```json
{
  "queries": [
    "nike.com"
  ],
  "searchMode": "ads",
  "adFormat": "ALL",
  "includeCreativeDetails": false,
  "maxAdsPerTarget": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All ads returned for the requested advertisers, as JSON.

## `adsCsv` (type: `string`):

The same ads as a CSV file, ready for Excel or Google Sheets.

## `datasetView` (type: `string`):

Open the results table in Apify Console.

# 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 = {
    "queries": [
        "nike.com"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("elhadj.hamlaoui/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 = {
    "queries": ["nike.com"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("elhadj.hamlaoui/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 '{
  "queries": [
    "nike.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call elhadj.hamlaoui/ads-transparency-scraper --silent --output-dataset

```

## MCP server setup

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