# Google Ads Transparency Scraper & Alerts | $1.50/1K (`layerwiselabs/google-ads-transparency-monitor`) Actor

Scrape competitors' Google ads from the Ads Transparency Center, Google's public ad library: ad copy of text ads as headline and description (OCR), images, YouTube videos, regions, platforms and impressions. Monitor advertisers and get Slack, Discord, webhook or e-mail alerts for new ads.

- **URL**: https://apify.com/layerwiselabs/google-ads-transparency-monitor.md
- **Developed by:** [Layerwise Labs](https://apify.com/layerwiselabs) (community)
- **Categories:** Marketing, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 ad returneds

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

### What does Google Ads Transparency Scraper & New Ad Alerts do?

It pulls your competitors' Google ads out of the [Google Ads Transparency Center](https://adstransparency.google.com), Google's public ad library, as clean, structured data, and it can **watch advertisers for you and send an alert when they launch a new ad**: to Slack, Discord, any webhook (Make, Zapier, n8n) or by e-mail.

Give it a website domain (`nike.com`), an advertiser name (`Zalando SE`), an advertiser ID or a Transparency Center URL. For every ad you get:

- **The words of text ads**: headline, description and display URL. The Transparency Center shows search ads only as pictures; this Actor reads them with OCR, so you can search, compare and analyse the copy.
- **Images and videos**: image URL of image and shopping ads (with the product title), YouTube link, title and channel of video ads.
- **Where and how much**: countries with the first and last day shown, impressions per country and per platform (Search, YouTube, Shopping, Maps, Play), topic, number of variations.
- **When**: first shown, last shown, days running, plus a direct link to the ad in the Transparency Center.

### At a glance

| | This Actor | Other Ads Transparency scrapers |
|---|---|---|
| New ads sent straight to Slack, Discord, a webhook or e-mail, with the ads in the message | ✅ built in | ❌ only a dataset; alerts need a separate integration |
| Alert missed because Slack or your server was down | ✅ sent again with the next run | ❌ no second try |
| Text ads as `headline`, `description` and `displayUrl` | ✅ included | often missing or a paid add-on |
| Regions, impressions per country and platform, ad text: total price | ✅ **$1.50 per 1,000 ads** | $2 to $7 per 1,000 ads |
| Start fee | ✅ none | often $0.001 to $0.005 per run |
| Start from a domain, a company name, an advertiser ID or a link | ✅ all four | usually some of them |

### Why use it?

- **Alerts are built in.** Other scrapers can return only new ads, but getting told about them means wiring up a separate integration. Here you switch on *Only new ads*, add a Slack, Discord, webhook or e-mail target, and schedule the Actor. Each alert lists the new ads with their headline and a link, and runs that find nothing new cost nothing.
- **Ad copy as text, not as a picture.** Google shows search ads only as images. The Actor reads them with OCR in the language of the region and uses the link colour to tell the headline from the description, so you get `headline`, `description` and `displayUrl` as separate fields you can search and compare.
- **Start from what you know.** A domain, a company name, an advertiser ID or a link all work. A name finds every account of that company (legal forms like GmbH, Inc. or S.p.A. do not matter), so you do not have to look up IDs first.
- **More per ad.** Impressions per country and platform, topic, number of variations, product titles of shopping ads, and title and channel of YouTube ads.
- **Runs that finish.** Google blocks IPs that send many requests. When that happens, the Actor moves the affected requests to residential proxy IPs by itself, gives each retry a fresh IP, and goes back to the direct connection once the block has passed. You do not need to configure a proxy, and the proxy traffic is included in the price.
- **Every Apify feature included**: scheduling, API, webhooks, exports to JSON, CSV, Excel, Google Sheets, and 1,500+ integrations.

### Who uses it

- **Marketing and PPC teams** tracking which messages, offers and creatives competitors test, and in which countries.
- **Agencies** preparing pitches and monthly competitor reports.
- **Brand protection** teams spotting ads that use their brand or domain.
- **Sales and lead generation**: find companies that actively advertise in a market or on YouTube.
- **Researchers and journalists** analysing advertising at scale.

### How to use it

1. Enter one or more **advertisers**: a domain such as `zalando.de`, a name such as `Zalando SE`, an advertiser ID such as `AR17568630107302526977`, or a URL copied from the Transparency Center.
2. Pick a **region** (country), and optionally a platform, an ad format and a date range.
3. Set **Max ads per advertiser** and click **Start**.
4. Download the ads from the **Output** tab, or read them through the API.

**To monitor competitors:** switch on **Only new ads**, add a Slack, Discord, webhook or e-mail target, save the input as a **task**, and give the task a **schedule** (for example every morning). The first run records the ads that already exist and returns nothing. Every later run returns only ads that were not there before and sends one alert with all of them.

### How much does it cost to scrape Google Ads Transparency?

Pay per event: **$1.50 per 1,000 ads** returned ($0.0015 per ad). Apify platform usage and proxies are included, there is no start fee, and monitoring runs that find no new ads are free. An ad whose details or preview Google's servers fail to deliver comes free of charge.

| What you do | Price |
|---|---|
| 100 ads of one competitor with text, images, regions and impressions | $0.15 |
| 1,000 ads | $1.50 |
| Daily monitoring of 10 competitors that launch 5 new ads a week each | about $0.32 per month |

Free Apify plan users get $5 of credit every month, which is more than 3,000 ads.

### Input

| Field | What it does |
|---|---|
| `advertisers` | Domains, advertiser names, advertiser IDs or Transparency Center URLs. A domain returns every advertiser that promotes it. A name matches all accounts with that name (legal forms such as GmbH or Inc. do not matter); if none matches, the log lists similar advertisers. Ads found through several entries are returned once. |
| `region` | Two-letter country code (`DE`, `US`, `RS`, …) or `anywhere`. |
| `platform` | `all`, `search`, `youtube`, `shopping`, `maps` or `play`. |
| `adFormat` | `all`, `text`, `image` or `video`. |
| `shownInLastDays`, `dateFrom`, `dateTo` | Only ads shown in this period. |
| `maxAdsPerAdvertiser` | Ads returned per advertiser, most recently shown first. Monitoring checks up to 5,000 per run and returns at most this many new ones; the rest follow with the next run. |
| `includeDetails` | Regions, impressions, platforms, topic and variations (one extra request per ad). |
| `includeAdContent` | Text of text ads (OCR), product titles and images, video links and titles. |
| `onlyNewAds`, `monitorName` | Monitoring: return only ads not seen in an earlier run. |
| `slackWebhookUrl`, `discordWebhookUrl`, `webhookUrl`, `notifyEmail` | Where to send alerts about new ads. E-mail alerts go to the e-mail address of your Apify account. |
| `ocrLanguages` | Language for reading text ads, e.g. `deu` or `fra`. Defaults to the language of the region. |
| `proxyConfiguration` | Leave it off: the Actor connects directly and moves to residential Apify Proxy by itself while Google blocks it. A proxy set here is used first, with residential Apify Proxy and the run's own IP as backup. |

Example:

```json
{
  "advertisers": ["zalando.de", "Zalando Marketing Services GmbH"],
  "region": "DE",
  "maxAdsPerAdvertiser": 100,
  "onlyNewAds": true,
  "slackWebhookUrl": "https://hooks.slack.com/services/…"
}
```

### Output

One item per ad. A text ad:

```json
{
  "advertiserId": "AR15589870916631265281",
  "advertiserName": "Zalando SE",
  "creativeId": "CR03015864204902006785",
  "format": "text",
  "adUrl": "https://adstransparency.google.com/advertiser/AR15589870916631265281/creative/CR03015864204902006785?region=DE",
  "firstShown": "2024-09-11T22:22:05Z",
  "lastShown": "2026-10-21T18:51:44Z",
  "daysShown": 381,
  "headline": "Winterstiefel & Schneestiefel online bei ZALANDO",
  "description": "Warme Winterstiefel, Snowboots und Schneestiefel halten dich auch bei Minusgraden warm | Glattleder Veloursleder Lederimitat gefüttert",
  "displayUrl": "www.zalando.de/",
  "imageUrl": "https://tpc.googlesyndication.com/archive/simgad/11815649257317532177",
  "variationCount": 3,
  "platforms": ["search", "youtube"],
  "impressionsMin": 5000,
  "impressionsMax": 6000,
  "regionStats": [
    {
      "region": "DE",
      "regionName": "Germany",
      "firstShown": "2024-09-11",
      "lastShown": "2026-10-21",
      "impressionsMin": 5000,
      "impressionsMax": 6000,
      "platforms": [
        { "platform": "search", "impressionsMin": 5000, "impressionsMax": 6000 },
        { "platform": "youtube", "impressionsMin": 0, "impressionsMax": 1000 }
      ]
    }
  ],
  "query": "zalando.de",
  "region": "DE"
}
```

A video ad has `videoUrl`, `videoThumbnailUrl`, `videoTitle` and `videoChannel`; an image or shopping ad has `imageUrl`, `imageUrls` and the product title in `adText`. In monitoring mode every item also has `isNew: true`.

The webhook alert is a JSON POST with `monitor`, `newAdsCount`, `runUrl` and `newAds` (the main fields of each new ad; the full items are in the run's dataset). More than 100 new ads are sent in several posts, numbered by `part` and `parts`.

### Use it through the API

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("layerwiselabs/google-ads-transparency-monitor").call(run_input={
    "advertisers": ["nike.com"],
    "region": "US",
    "platform": "youtube",
    "maxAdsPerAdvertiser": 50,
})
for ad in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(ad["advertiserName"], ad["videoTitle"], ad["videoUrl"])
```

AI agents can call the Actor through the [Apify MCP server](https://mcp.apify.com) as a tool, for example "show me the ads Zalando launched in Germany this week".

### FAQ

#### How does the new-ad alert work?

With *Only new ads* on, the first run records all ads the advertiser has (up to 5,000 per advertiser, whatever the date filters say), separately per task or monitor name, region, platform and format. Every later run checks the most recently shown ads, back to a week before the previous check and up to 5,000 (checking is free), and returns, and alerts about, those that were not recorded before. Old ads that start running again are not reported as new. An advertiser given by name stays tied to the accounts found on the first run. If an alert cannot be delivered, for example because Slack is down, it is sent with the next run.

If a run of the same monitor is still going when the next one starts, the new run stops right away, so no ad is reported twice. Running several monitors with the same advertisers through the API? Give each one its own *Monitor name*.

#### Why does the first monitoring run return no ads?

It records the advertiser's current ads as the starting point, so that you are not alerted about hundreds of old ads. You are not charged for it.

#### How exact is the text of text ads?

The Transparency Center only provides text ads as images, so the Actor reads them with OCR (Tesseract, in the language of the selected region). Headline, description and display URL come out correctly in the vast majority of cases; rare characters or unusual layouts can be misread. `imageUrl` always links the original image.

#### Can I get the landing page URL?

Google does not publish the click URL of most ads in the Transparency Center. When an ad preview contains one, it is in `landingUrl`. `displayUrl` shows the domain the ad displays.

#### Why are impressions missing for some ads?

Google publishes impression ranges only for some ads and regions. Where Google gives none, the fields are `null`.

#### The run says Google blocked requests. What should I do?

Usually nothing: the Actor moves blocked requests to residential proxy IPs and retries them from new IPs. If a request still fails after all retries, the log says which advertiser or ad is affected, and a new run picks it up.

#### Is it legal to scrape the Google Ads Transparency Center?

The Transparency Center is public: Google publishes these ads so that anyone can see them. The Actor collects only this public information about advertisers and their ads, no personal data of users. Check that your use complies with the laws that apply to you and with Google's terms.

#### Something does not work

Open an issue in the **Issues** tab with the input you used, and we will look into it.

# Actor input Schema

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

Whose ads to get. Each line is a website domain (nike.com), an advertiser name (Zalando SE), an advertiser ID (AR17568630107302526977) or a Transparency Center URL. A domain returns every advertiser that promotes it.

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

Only ads shown in this country.

## `platform` (type: `string`):

Only ads shown on this Google service.

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

Only ads of this format.

## `shownInLastDays` (type: `integer`):

Only ads shown within this many days before today (up to about 365, as far as Google's date filter reaches). Overrides 'Shown from'. 0 = no limit.

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

Only ads shown on or after this day, YYYY-MM-DD. Google's date filter covers about the last 12 months.

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

Only ads shown on or before this day, YYYY-MM-DD.

## `maxAdsPerAdvertiser` (type: `integer`):

How many ads to return per line in Advertisers, most recently shown first. With 'Only new ads', each check looks through up to 5,000 ads and returns at most this many new ones; any others follow with the next run.

## `includeDetails` (type: `boolean`):

Per ad: countries with first and last day shown, impressions per country and platform, topic and all variations. One extra request per ad.

## `includeAdContent` (type: `boolean`):

Reads headline, description and display URL of text ads (OCR), product titles and images of image ads, and YouTube link, title and channel of video ads.

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

Remembers which ads each advertiser already had and returns only ads launched since the previous check. The first run saves the current ads as a baseline and returns nothing. Schedule the Actor (for example daily) to watch competitors.

## `monitorName` (type: `string`):

Keeps separate memories for different monitors with the same advertisers. Saved tasks get their own memory automatically.

## `slackWebhookUrl` (type: `string`):

Posts new ads to a Slack channel (Incoming Webhook URL). Needs 'Only new ads'.

## `discordWebhookUrl` (type: `string`):

Posts new ads to a Discord channel. Needs 'Only new ads'.

## `webhookUrl` (type: `string`):

Sends the new ads as JSON in a POST request, for example to Make, Zapier or n8n. Needs 'Only new ads'.

## `notifyEmail` (type: `string`):

Sends new ads by e-mail through the apify/send-mail Actor (billed to your account as a few cents of platform usage). Use the e-mail address of your Apify account. Needs 'Only new ads'.

## `ocrLanguages` (type: `string`):

Tesseract language codes for reading text ads, e.g. 'deu' or 'fra+eng'. Empty = the language of the region; with 'Anywhere', the language of the country where each ad was shown most.

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

Ads processed in parallel (previews, images and text recognition). Requests to the Transparency Center itself always run one after another, which keeps blocks by Google rare.

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

Leave it off: the Actor connects directly and moves to residential Apify Proxy by itself while Google blocks it. A proxy set here is used first, with residential Apify Proxy and the run's own IP as backup.

## Actor input object example

```json
{
  "advertisers": [
    "zalando.de"
  ],
  "region": "DE",
  "platform": "all",
  "adFormat": "all",
  "shownInLastDays": 0,
  "maxAdsPerAdvertiser": 20,
  "includeDetails": true,
  "includeAdContent": true,
  "onlyNewAds": false,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One item per ad: advertiser, format, first and last shown, headline, description, images, video and link to the Transparency Center.

## `regions` (type: `string`):

Countries where each ad was shown, with dates and impressions per platform.

# 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": [
        "zalando.de"
    ],
    "region": "DE",
    "maxAdsPerAdvertiser": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("layerwiselabs/google-ads-transparency-monitor").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": ["zalando.de"],
    "region": "DE",
    "maxAdsPerAdvertiser": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("layerwiselabs/google-ads-transparency-monitor").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": [
    "zalando.de"
  ],
  "region": "DE",
  "maxAdsPerAdvertiser": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call layerwiselabs/google-ads-transparency-monitor --silent --output-dataset

```

## MCP server setup

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

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/riAnxoyBhjlsWbZZj/builds/xflInYSXeomh4uPtd/openapi.json
