# Google Ads Transparency Scraper & Competitor Ad Monitor (`yushi3/google-ads-transparency-monitor`) Actor

Scrape any advertiser's Google ads by domain or advertiser ID: text-ad headlines, descriptions and sitelinks (OCR), format, first and last shown dates. Monitor mode flags ads that started or stopped running since the last run, with webhook alerts. Pay per ad.

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

## Pricing

from $2.00 / 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 & Competitor Ad Monitor

See every ad a competitor runs on Google, from the public [Google Ads Transparency Center](https://adstransparency.google.com), and get told when they launch or pull one. Enter a domain (`nike.com`) or advertiser ID. Each ad comes back as a flat row: format, first and last shown dates, days running, media links and, for search ads, the **headline, description, display URL and sitelinks**. The Transparency Center shows these only as images, so the Actor reads them with OCR.

- **Text-ad copy included**: headlines, descriptions, display URLs and sitelinks are read from the ad preview with PP-OCRv6, which handles 50 languages, including Japanese, Chinese and European languages. Each ad is read once and remembered, so repeat runs don't pay to read it again.
- **Competitor monitoring built in**: every row says whether the ad is `newSinceLastRun` or `stoppedSinceLastRun`. Turn on **Only new and stopped ads** to get (and pay for) only the changes, and add a webhook to be alerted about each one (to Slack, email or a spreadsheet via Zapier, Make or n8n).
- **Every format**: text (search) ads with their copy, Shopping ads with product title, merchant and image, product-feed display ads with the product photo, video ads with their YouTube link, and image ads with the creative's image URL. Optional country and format filters.
- **API and AI agent tool**: ask "what ads is this advertiser running?" in one API call, or let an AI agent call it as a tool through the Apify MCP server.
- **No browser, no login, no proxy needed**: plain HTTP requests.

### Use cases

- Watch competitors' Google Ads: get a Slack message the day they launch a new campaign or stop an old one.
- Collect competitors' search ad copy (headlines, descriptions, sitelinks) to benchmark messaging and offers.
- Track how long ads run (`firstShown`, `lastShown`, `daysShown`) to spot the ones that work.
- Feed ad copy into an LLM for analysis, or give an AI agent a "what is X advertising?" tool.

### How to use it

1. Add **Advertisers**: a domain (`nike.com`), a website URL, a Google advertiser ID (`AR16735076323512287233`) or an Ads Transparency Center link. A domain returns every advertiser account that runs ads for it.
2. Optionally set a **Region** (`US`, `GB`, `DE`…) and an **Ad format**.
3. Choose **Max ads per advertiser** (default 50, most recently shown first).
4. For monitoring, turn on **Only new and stopped ads**, optionally set an **Alert webhook URL**, and run the Actor on a [schedule](https://docs.apify.com/platform/schedules), for example daily. The first run returns everything and becomes the baseline; later runs return only ads that started or stopped running.

The Actor stores which ads it has seen, and their text, per advertiser in your account's key-value store `google-ads-transparency-monitor-state`.

### Tutorial: get a Slack message when a competitor launches or stops a Google ad

1. In [Zapier](https://zapier.com), [Make](https://www.make.com) or [n8n](https://n8n.io), create a scenario that starts with a **webhook trigger** ("Catch Hook" in Zapier, "Custom webhook" in Make, "Webhook" node in n8n) and copy its URL.
2. Add a **Slack → Send message** step. Map `item.advertiserName`, `item.format`, `item.headline`, `item.description` and `item.adUrl` into the message, and use `item.newSinceLastRun` / `item.stoppedSinceLastRun` to say whether the ad started or stopped.
3. In this Actor, enter your competitors' domains under **Advertisers** (e.g. `hubspot.com`), set a **Region** if you only care about one country, turn on **Only new and stopped ads**, and paste the webhook URL into **Alert webhook URL**.
4. Run it once. That run records the ads already live as the baseline and sends no alerts.
5. Open **Schedules** in Apify Console and run the Actor daily with the same input. Each launched or stopped ad then becomes one Slack message, and you pay only for those ads.

To keep a history of every competitor ad instead, connect the Actor's dataset to Google Sheets with Apify's [Google Sheets integration](https://apify.com/lukaskrivka/google-sheets) and turn **Only new and stopped ads** off.

### Input

```json
{
  "advertisers": ["nike.com", "AR16735076323512287233"],
  "region": "US",
  "adFormat": "all",
  "maxAdsPerAdvertiser": 50,
  "extractAdText": true,
  "onlyChanges": true,
  "alertWebhookUrl": "https://hooks.example.com/google-ads"
}
```

| Field | Required | Description |
| --- | --- | --- |
| `advertisers` | yes | Domains, website URLs, advertiser IDs (`AR…`) or Ads Transparency Center links. |
| `region` | no | Two-letter country code, or `anywhere` (default). A `region` in a Transparency Center link takes priority. |
| `adFormat` | no | `all` (default), `text`, `image` or `video`. |
| `maxAdsPerAdvertiser` | no | 1 to 5,000 ads per advertiser (default 50), most recently shown first. |
| `extractAdText` | no | Read text-ad copy with OCR (default `true`; included in the price). |
| `onlyChanges` | no | Return only ads that started or stopped running since the previous run (default `false`). |
| `alertWebhookUrl` | no | Receives a POST for every ad that started or stopped running since the previous run. |
| `proxyConfiguration` | no | Leave empty: Google is fetched directly, falling back to Apify datacenter and then residential proxies only if it rate-limits the run. |

### Output

One dataset item per ad:

```json
{
  "adId": "CR03473167961525583873",
  "advertiserId": "AR16735076323512287233",
  "advertiserName": "Nike, Inc.",
  "adUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR03473167961525583873?region=US",
  "format": "text",
  "headline": "Nike® Official Site - Browse Kids Tops",
  "description": "Let them feel comfortable and confident in what they wear. Pullovers made for them…",
  "displayUrl": "www.nike.com/shop/pullovers",
  "sitelinks": [{ "title": "Kids' Price In Cart", "description": "Shop select kids' styles & see new prices when added to your cart." }],
  "adText": "Nike\nwww.nike.com/shop/pullovers\nNike® Official Site - Browse Kids Tops\n…",
  "firstShown": "2023-11-17T04:15:01.000Z",
  "lastShown": "2026-10-25T17:31:16.000Z",
  "daysShown": 1073,
  "isRunning": true,
  "region": "US",
  "imageUrl": "https://tpc.googlesyndication.com/archive/simgad/…",
  "videoUrl": null,
  "previewUrl": null,
  "newSinceLastRun": false,
  "stoppedSinceLastRun": false,
  "source": "https://adstransparency.google.com/?domain=nike.com&region=US",
  "scrapedAt": "2026-10-25T18:01:12.511Z"
}
```

- `isRunning` is `true` when Google showed the ad in the last 48 hours. `stoppedSinceLastRun` is `true` when it was running at the previous run and no longer is. An ad that drops out of the newest-ads window is still re-checked by ID, so stopped ads are caught even when many new ads push them down the list.
- Shopping ads put the product title in `headline` and the merchant in `displayUrl`. Video ads carry `videoUrl` (YouTube) when the video is on YouTube. Image ads carry the creative in `imageUrl`.
- Text fields are `null` for plain image and video ads, and for local (map) ads that have no headline. `adText` always holds everything that was read.
- `previewUrl` is Google's preview script for the creative.

The webhook body is `{ "actor": "google-ads-transparency-monitor", "item": { ...same fields... }, "detectedAt": "<ISO time>" }`.

### API and AI agents

Run it and get the results in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/yushi3~google-ads-transparency-monitor/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"advertisers": ["nike.com"]}'
```

It returns the dataset items as a JSON array. AI agents can call the Actor as a tool through the [Apify MCP server](https://mcp.apify.com).

### Pricing

| Event | Price |
| --- | --- |
| Ad returned (text-ad copy included) | $0.002 |
| Ad change alert delivered to your webhook | $0.002 |

With **Only new and stopped ads** on, ads you already received are neither returned nor charged, so a daily competitor monitor costs only for real changes. Nothing is charged for an advertiser that fails, and failed webhook deliveries are not billed.

### Limitations

- Only what the Ads Transparency Center shows publicly. It doesn't show spend, impressions (except for EU political ads), targeting or keywords.
- Text-ad copy comes from OCR. Clean English and CJK previews read almost perfectly. Previews that put a product photo next to the text can pick up a few stray characters.
- Video ads hosted outside YouTube come with an image but no video link.
- Some display ads (HTML5 and rich media) appear in the Transparency Center only as a blank placeholder. They come with no image.

### When an advertiser fails

Every advertiser is processed even if one fails. Failures are listed in the run's key-value store under `FAILED_TARGETS` with the reason, such as a Google rate limit. The run fails outright only when Google changed its data format in a way the Actor can no longer read (it is re-tested against the live site every 12 hours) or when every advertiser failed.

### Questions and issues

Open an issue on the Actor's **Issues** tab.

# Actor input Schema

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

Competitors to track: a website domain (nike.com), a website URL, a Google advertiser ID (AR16735076323512287233) or an Ads Transparency Center link (https://adstransparency.google.com/advertiser/AR16735076323512287233?region=US). A domain returns every advertiser account that runs ads for it.

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

Only ads shown in this country: a two-letter code such as US, GB or DE. Leave as "anywhere" for ads shown in any country. A region in an Ads Transparency Center link takes priority.

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

Only return ads of this format.

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

Stop after this many ads for each advertiser, most recently shown first.

## `extractAdText` (type: `boolean`):

Google shows search (text) ads only as images: when on, their headline, description, display URL and sitelinks are read with OCR in any of 50 languages. Shopping ads get the product title, merchant and image; video ads the YouTube link; image ads the creative's image URL. Each ad is read once and remembered for later runs. Included in the per-ad price.

## `onlyChanges` (type: `boolean`):

Return (and charge for) only ads that started running, or stopped running, since the previous run of this actor for the same advertiser. The first run returns everything and becomes the baseline. Turn on for scheduled competitor monitoring.

## `alertWebhookUrl` (type: `string`):

Optional. Receives a POST for each ad that started or stopped running since the previous run (Slack, Zapier, Make or n8n webhooks work).

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

Optional. By default the Transparency Center is fetched directly and only falls back to Apify datacenter, then residential proxies when Google rate-limits the run. Set a proxy here to use it for every request instead.

## Actor input object example

```json
{
  "advertisers": [
    "https://adstransparency.google.com/advertiser/AR16735076323512287233?region=US"
  ],
  "region": "anywhere",
  "adFormat": "all",
  "maxAdsPerAdvertiser": 12,
  "extractAdText": true,
  "onlyChanges": false
}
```

# Actor output Schema

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

One item per ad: format, text-ad copy, media links, first and last shown dates, and whether it started or stopped running since the previous run.

# 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": [
        "https://adstransparency.google.com/advertiser/AR16735076323512287233?region=US"
    ],
    "maxAdsPerAdvertiser": 12
};

// Run the Actor and wait for it to finish
const run = await client.actor("yushi3/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": ["https://adstransparency.google.com/advertiser/AR16735076323512287233?region=US"],
    "maxAdsPerAdvertiser": 12,
}

# Run the Actor and wait for it to finish
run = client.actor("yushi3/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": [
    "https://adstransparency.google.com/advertiser/AR16735076323512287233?region=US"
  ],
  "maxAdsPerAdvertiser": 12
}' |
apify call yushi3/google-ads-transparency-monitor --silent --output-dataset

```

## MCP server setup

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