# Google Ads Transparency Scraper & Monitor (`lyklo/google-ads-monitor`) Actor

Tracks your competitors' Google ads from the Ads Transparency Center: new, stopped and resumed ads, in several countries at once, with a summary per advertiser.

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

## Pricing

from $3.00 / 1,000 ad changes

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 & Monitor

Know when a competitor starts, stops or brings back a Google ad. Give it the websites of the companies you watch, pick the countries, and schedule it. Each run tells you what changed since the last one, plus a one-line summary per competitor.

The data comes from Google's public [Ads Transparency Center](https://adstransparency.google.com), which lists the ads that verified advertisers run on Google Search, YouTube, Display, Shopping, Maps and Play. This is an independent tool. It is not made, endorsed or sponsored by Google.

### Who it's for

- **In-house marketers at e-commerce and D2C brands**: get a morning digest of your competitors' new and stopped ads in Slack or a spreadsheet, so you notice a sale or a new campaign the day it starts.
- **Agencies and freelance ad managers**: run one watch per client and drop the weekly summary into your report: how many ads each competitor runs, what is new, what has been running the longest.
- **Sales teams**: check whether a company advertises on Google before you reach out, and since when.
- **Developers**: pull the full ad list into your own database through the API.

### How to use it

1. Enter your competitors, one per line. A domain (`acme.com`) works best. You can also use an advertiser ID from the Transparency Center (`AR…`) or a company name. A name covers every advertiser registered under exactly that name (for example a brand's US and German companies), and the run log lists which ones were used. If no advertiser has that exact name, the log shows the closest ones with their IDs, and that line is skipped.
2. Pick one or more countries.
3. Leave **What to return** on *Changes since the last run*.
4. Save it as a task and add a daily or weekly schedule in Apify.
5. Optional: connect the task to Slack, Google Sheets, a webhook or Zapier/Make with Apify's integrations.

The first run records the ads the competitor has shown recently as `baseline`. From the second run on, you only get the ads that changed.

Use a different **Watch name** for each separate list (for example one per client). Runs with the same watch name share their memory of what was seen before.

### What you get

#### One row per ad change

| Field | Meaning |
| --- | --- |
| `change` | `new`, `stopped`, `resumed`, `newRegion`, `newVariation`, or `baseline` on the first run. In *All ads* mode it is `listed` |
| `target`, `region` | The competitor you entered and the country |
| `advertiserName`, `advertiserId` | The verified advertiser behind the ad. One website can have several advertisers (for example a brand's US and Japanese companies) |
| `format` | `text`, `image` or `video` |
| `firstShown`, `lastShown`, `daysShown` | When the ad was first and last shown, and on how many days |
| `isActive` | Whether it was shown within the last *N* days (7 by default) |
| `imageUrl` | A picture of the ad. For text ads this is Google's rendering of the ad |
| `adUrl` | The ad's page in the Transparency Center |
| `regionsShown`, `variations` | With **Add ad details**: the countries where it ran, with impression ranges where Google publishes them (mainly in the EU), and the number of variations |

#### One summary row per competitor and country

Running ads, how many are new or stopped since the last run, how many of the running ads started in the last 7 and 28 days, a split by format, the five longest-running ads (often the ones that work) and the five newest ads. `complete` is `false` when the ad count stopped at your maximum; the counts then cover only the ads that were read.

### Pricing

You pay per event, so a day with no changes costs only the run and the summary rows.

| Event | Price |
| --- | --- |
| Run start | $0.005 per run (with the default memory) |
| Ad change: `new`, `stopped`, `resumed`, `newRegion`, `newVariation` | $3.00 per 1,000 |
| Ad listed: `baseline` on the first run, *All ads* mode, or unchanged ads when you ask for them | $0.75 per 1,000 |
| Summary row, one per competitor and country | $0.005 each |
| Ad details, only with **Add ad details** | $1.00 per 1,000 ads |

For example, watching 10 competitors in one country every day, with about 150 ads each and 3% of them changing a day, costs about $1 for the first run and about $6 a month after that. Set a maximum cost per run in Apify if you want a hard limit; the run stops cleanly when it is reached, and the changes it could not report come out on the next run.

### Good to know

- **One run per watch at a time.** If a run starts while another run is still using the same watch name, it stops with an error instead of reporting the same changes twice. Give overlapping schedules different watch names.
- **"Advertising" can be unknown.** When the ad cap stops a search before any running ad is found, `isAdvertising` is `null`, not `false`.
- **Ad rows and summary rows share one dataset.** Each row has `type` (`ad` or `summary`). Filter on it when you export or connect the results to a spreadsheet.
- **Names can be ambiguous.** Different companies sometimes share a name (for example "Nike" also matches unrelated companies called Nike in other countries). Use the website domain when you can.
- **Changing "Count an ad as stopped after" is safe.** The previous run's ads are re-checked with the new number of days, so it doesn't create false stopped or resumed ads.
- **"Stopped"** means an ad has not been shown for the number of days you set (7 by default), or it no longer appears in the Transparency Center.
- **Large advertisers can have thousands of ads.** Google lists ads by the date they were last shown, so in *Changes* mode each run reads only the ads shown since shortly before the previous run and stops there. That covers every ad that can have changed, even for an advertiser with thousands of old ads. The *Maximum ads per competitor and country* setting matters only when a competitor shows more ads than that at the same time (Nike runs well over 1,000 a day in the US). Then the run log warns you: new ads beyond the cap can be missed, and ads beyond it are never reported as stopped. Raise the cap for that competitor.
- **"New" means first shown recently.** An ad counts as new when Google first showed it after the previous run, or up to 3 days before it, because some ads reach the Transparency Center late. Google sometimes adds an ad that has run for years to its list; such an ad is recorded quietly instead of being reported as new.
- **Changing the format filter starts a fresh watch** for that competitor and country, so you don't get a flood of false "stopped" ads.
- The Transparency Center shows ads from verified advertisers only. Ad text inside text ads is shown as an image, not as text.

# Actor input Schema

## `targets` (type: `array`):

One competitor per line: a website domain (acme.com), an advertiser ID from the Ads Transparency Center (AR…), or an advertiser name. A name is matched to every advertiser with exactly that name (ignoring Inc., GmbH and similar), and the run log lists them. If none has that exact name, the run log shows the closest advertisers and their IDs.

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

Countries to check. Each competitor is checked in every country you pick, and each country gets its own results.

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

Changes: only what changed since the last run with the same watch name (the first run records the recently shown ads). All ads: every ad found, every run. Summaries only: one row per competitor and country, for checking whether a company advertises.

## `watchName` (type: `string`):

Keeps the memory of past runs separate for each watch, for example one per client. Letters, numbers and dashes.

## `formats` (type: `array`):

Leave empty for all formats.

## `stoppedAfterDays` (type: `integer`):

An ad not shown for this many days is reported as stopped.

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

Adds the countries where each ad was shown (with impression ranges where Google publishes them, mainly in the EU) and the number of ad variations. Also lets the monitor spot ads that reach new countries or get new variations. Charged per returned ad that includes details.

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

In Changes mode a run reads only the recently shown ads, so this matters only for very large advertisers. Raise it if the log says the cap was hit. In All ads and Summaries only modes it caps the ads read for each competitor and country.

## `includeUnchanged` (type: `boolean`):

In change mode, also return ads that did not change. They are charged like listed ads.

## Actor input object example

```json
{
  "targets": [
    "nike.com"
  ],
  "regions": [
    "US"
  ],
  "mode": "monitor",
  "watchName": "default",
  "formats": [],
  "stoppedAfterDays": 7,
  "includeDetails": false,
  "maxAdsPerTarget": 20,
  "includeUnchanged": false
}
```

# Actor output Schema

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

One dataset with two kinds of rows, told apart by the type field. Rows with type "ad" are ads that changed since the last run (new, stopped, resumed, newRegion, newVariation), or baseline on the first run and listed in All ads mode. Rows with type "summary" are one per competitor and country: whether it advertises, running ads, new and stopped counts, and the longest-running and newest ads.

# 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 = {
    "targets": [
        "nike.com"
    ],
    "regions": [
        "US"
    ],
    "maxAdsPerTarget": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("lyklo/google-ads-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 = {
    "targets": ["nike.com"],
    "regions": ["US"],
    "maxAdsPerTarget": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("lyklo/google-ads-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 '{
  "targets": [
    "nike.com"
  ],
  "regions": [
    "US"
  ],
  "maxAdsPerTarget": 20
}' |
apify call lyklo/google-ads-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lyklo/google-ads-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/ERn89G5lZna19DoEt/builds/cWYPXR7W0pIh5eydk/openapi.json
