# Google Ads Transparency Scraper (Competitor Ad Monitor) (`signalclear/google-ads-transparency-scraper`) Actor

Every ad a competitor runs on Google Search, YouTube, Shopping, Maps and Play, from Google's public Ads Transparency Center. Paste advertiser names, domains or AR ids; filter by country, format, platform and dates. Bounded retries; failed advertisers are never charged.

- **URL**: https://apify.com/signalclear/google-ads-transparency-scraper.md
- **Developed by:** [signal clear](https://apify.com/signalclear) (community)
- **Categories:** Marketing
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

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

Pull every ad a competitor is running on Google from the public
[Google Ads Transparency Center](https://adstransparency.google.com): Search text ads,
image ads, YouTube video ads, Shopping, Maps and Play. Give it advertiser names, website
domains or advertiser ids, and get one clean row per ad with first and last seen dates,
the preview image or preview link, and the public Transparency Center page for that ad.

Built for **competitor ad monitoring**: run it weekly (or daily in the run-up to Black
Friday and Cyber Monday) and see which creatives a rival launched, which ones they keep
running, and which ones they killed.

- Names, domains, `AR...` ids or Transparency Center URLs, mixed in one run
- Filters: country, platform, ad format, date range
- Bounded and cheap: a cap per advertiser and in total, gentle request pacing
- **Failed advertisers are never charged.** An advertiser's ads are saved only when the
  whole advertiser finished; anything that failed is listed in `FAILED_ADVERTISERS` and
  contributes nothing to the dataset.

### Input

| Field | What it does |
|---|---|
| `advertisers` | One per line. `Walmart Inc.` (name), `hubspot.com` (domain), `AR08902249778948079617` (advertiser id), or a Transparency Center URL such as `https://adstransparency.google.com/advertiser/AR...` or `https://adstransparency.google.com/?domain=hubspot.com`. |
| `region` | Two-letter country code (`US`, `GB`, `DE`, ...) or `anywhere` (default). |
| `platform` | `all`, `googleSearch`, `youtube`, `googleShopping`, `googleMaps`, `googlePlay`. |
| `adFormat` | `all`, `text`, `image`, `video`. |
| `dateFrom`, `dateTo` | Only ads shown in this window (`YYYY-MM-DD`). |
| `maxAdsPerAdvertiser` | Default 50. Newest first. |
| `includeAdvertiserInfo` | Adds one `type: "advertiser"` summary row per advertiser (counts as a result). |
| `includeCreativeDetails` | Adds regions (with per-region dates and impression ranges where Google publishes them), platforms, and every variant's preview. One extra request per ad. |
| `resolveVideoUrls` | Fills `videoUrl` with the YouTube link for video ads (downloads ~130 KB per video ad). |
| `maxItems` | Total ad cap across all advertisers (0 = no limit). |
| `maxConcurrency` | Advertisers processed in parallel. Default 2. |
| `maxAttempts` | Attempts per advertiser, each on a fresh proxy session. Default 3, max 5. |
| `proxyConfiguration` | Defaults to Apify datacenter proxy. |

**How names are matched.** A name is looked up with the site's own search box. If
several advertisers share that exact name (big brands often have several accounts), the
one with the most ads is used and the others are listed in the log; paste an `AR...` id to
choose one explicitly. A **domain** returns ads from every advertiser that advertises that
domain, which is usually what you want for competitor monitoring.

```json
{
  "advertisers": ["hubspot.com", "Walmart Inc.", "AR08902249778948079617"],
  "region": "US",
  "adFormat": "all",
  "maxAdsPerAdvertiser": 100
}
```

### Output

One row per ad:

```json
{
  "type": "ad",
  "advertiserId": "AR10072600183532683265",
  "advertiserName": "Hubspot, Inc.",
  "advertiserDomains": ["hubspot.com"],
  "creativeId": "CR05670001488131260417",
  "format": "text",
  "firstShown": "2022-06-24T01:19:16Z",
  "lastShown": "2026-10-28T09:46:38Z",
  "daysShown": 1576,
  "previewUrl": "https://tpc.googlesyndication.com/archive/simgad/739348024653901222",
  "imageUrl": "https://tpc.googlesyndication.com/archive/simgad/739348024653901222",
  "videoUrl": null,
  "creativeUrl": "https://adstransparency.google.com/advertiser/AR10072600183532683265/creative/CR05670001488131260417?region=US",
  "region": "US",
  "input": "hubspot.com",
  "scrapedAt": "2026-10-28T17:02:11.412Z"
}
```

- `format`: `text`, `image` or `video`. Google archives text ads as a rendered image, so
  text ads also have an `imageUrl`; the ad copy itself is not published as text.
- `previewUrl`: the image for image and text ads; for video and some rich ads, Google's
  preview script link (opens the rendered ad).
- `daysShown`: the number of days Google reports the ad as shown.
- With `includeCreativeDetails`: `regions` (`[{region, firstShown, lastShown, impressionsLow, impressionsHigh}]`),
  `platforms`, `variantPreviewUrls`, and total `impressionsLow` / `impressionsHigh`.
  Impression ranges are published for some regions only (mostly the EU).
- Landing pages and click-through URLs are not published by the Transparency Center.

Failures are written to the key-value store record `FAILED_ADVERTISERS`:

```json
[{"advertiser": "zzqx nonexistent brand", "error": "unknown advertiser: no advertiser named \"zzqx nonexistent brand\"", "attempts": 1}]
```

### How it works

The Transparency Center web page loads its data from a small public JSON API on the same
site; no login or key is needed. This Actor calls that API directly, the same requests your
browser makes when you use the site:

1. **Find the advertiser.** A name goes to the site's search suggestions
   (`POST /anji/_/rpc/SearchService/SearchSuggestions`), which returns matching advertisers
   with their `AR...` ids and rough ad counts. An id is confirmed with
   `LookupService/GetAdvertiserById`. A domain needs no lookup.
2. **List the ads.** `SearchService/SearchCreatives` returns up to 100 ads per request
   (about 360 bytes per ad) for an advertiser id or a domain, with the region, platform,
   format and date filters applied by Google, plus a cursor for the next page.
3. **Optional detail.** `LookupService/GetCreativeById` returns one ad's regions, dates,
   platforms, impression ranges and variants.

Each request is a form POST with a single `f.req` field holding JSON. Requests are paced
(1 to 2 seconds between pages of one advertiser) and parallelism is low by default.

**Geography.** The region is part of the request, so results depend only on the `region`
input, not on where the request comes from; any proxy country works.

**Blocks.** If Google answers with its "unusual traffic" page, a consent page, a rate limit
(429) or a server error, the attempt stops, waits, and the advertiser is retried on a new
proxy session from where it left off. The Actor never tries to solve a challenge. If an
advertiser still fails after `maxAttempts`, it is recorded in `FAILED_ADVERTISERS` and not
charged. The run fails only if every advertiser failed.

### Limits

- The API is undocumented. Google can change it at any time; when it does, this Actor
  fails loudly rather than returning wrong data, and will be updated.
- Some fields depend on the region: impression ranges, per-region dates and some
  advertiser details are only published for certain countries.
- Ad counts from Google are approximate ranges (for example "1000 to 2000").
- Ads are listed newest first. Very large advertisers have tens of thousands of ads; use
  the filters and `maxAdsPerAdvertiser` to keep runs bounded.
- Platform values follow the Transparency Center's own platform filter. Display network
  ads have no separate filter there.

### Pricing

Pay per result: you pay for ads saved to the dataset (and summary rows if you turn them
on). Failed advertisers produce no rows, so they cost nothing. Default settings use
datacenter proxy and about one request per 100 ads, so runs are cheap and fast.

### Legal

The Ads Transparency Center is a public archive that Google publishes so anyone can see
who is advertising and what they show. This Actor reads only that public data, collects no
personal data, and needs no account. Google's Terms of Service restrict automated access
to its services, so using this tool carries contractual risk with Google; you are
responsible for how you use the data and for complying with the terms that apply to you.

# Actor input Schema

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

One per line: an advertiser name ("Walmart Inc."), a website domain ("hubspot.com"), an advertiser id (AR followed by digits), or an adstransparency.google.com advertiser or domain URL. A name picks the exact-name match with the most ads; use an AR id to choose a specific one. A domain returns ads from every advertiser that runs ads for it.

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

Two-letter country code (US, GB, DE, ...) to list only ads shown in that country, or "anywhere" for all regions.

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

Only ads shown on this Google surface. Display network ads are not split out by the Transparency Center.

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

Only ads of this format.

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

Only ads shown on or after this date (YYYY-MM-DD). Leave empty for no lower bound.

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

Only ads shown on or before this date (YYYY-MM-DD). Leave empty for no upper bound.

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

Newest ads first. The site lists 100 ads per request.

## `includeAdvertiserInfo` (type: `boolean`):

Adds one row per advertiser (type "advertiser") with its name, legal name, country and Google's approximate ad count. The row counts as a result.

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

Adds the regions each ad ran in (with first/last dates and, where Google publishes them, impression ranges), the platforms it ran on, and every variant's preview link. Costs one extra request per ad.

## `resolveVideoUrls` (type: `boolean`):

For video ads, downloads the preview script (about 130 KB each) to find the YouTube video and fills videoUrl. Off by default because it is slow.

## `maxItems` (type: `integer`):

Stop after this many ads across all advertisers. 0 means no limit. Summary rows are not counted.

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

All requests go to one Google endpoint, so keep this low; higher values mostly trigger rate limits and retries.

## `maxAttempts` (type: `integer`):

Each attempt uses a fresh proxy session and resumes where the previous one stopped. Advertisers that still fail are listed in FAILED_ADVERTISERS and are not charged. Unknown advertisers are not retried.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for a single HTTP response before the attempt counts as failed and is retried on a fresh session.

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

Apify datacenter proxy works for this public endpoint. The proxy country does not change which ads you get; use the Region field for that. Switch to residential only if you see repeated "unusual traffic" failures.

## Actor input object example

```json
{
  "advertisers": [
    "hubspot.com"
  ],
  "region": "US",
  "platform": "all",
  "adFormat": "all",
  "maxAdsPerAdvertiser": 50,
  "includeAdvertiserInfo": false,
  "includeCreativeDetails": false,
  "resolveVideoUrls": false,
  "maxItems": 0,
  "maxConcurrency": 2,
  "maxAttempts": 3,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Dataset results in the "Ads" view.

## `images` (type: `string`):

Dataset results in the "Image previews" view.

## `failed` (type: `string`):

JSON list of advertisers that failed after every retry, with the error for each. Empty when everything succeeded. Failed inputs are never charged.

# 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": [
        "hubspot.com"
    ],
    "region": "US",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("signalclear/google-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 = {
    "advertisers": ["hubspot.com"],
    "region": "US",
    "proxyConfiguration": { "useApifyProxy": True },
}

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

```

## MCP server setup

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