# Google Ads Transparency Scraper: Competitor Ad Library (`mosaicked_sponge/google-ads-transparency-scraper`) Actor

See every competitor ad in the Google Ads Transparency Center. Search by brand, website or advertiser ID and get ad text, images, YouTube videos, format, first and last shown dates, regions and EU reach. No login, no proxy fees.

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

## Pricing

from $1.50 / 1,000 ads

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 Library

Pull **every ad a company runs on Google** (Search, YouTube, Shopping, Maps and Play) from the public [Google Ads Transparency Center](https://adstransparency.google.com). Search by **website**, **brand name** or **advertiser ID** and get one clean row per ad: format, first and last shown, days running, every country it ran in, **headline and description**, landing page, **image and YouTube video links**, EU **impressions ranges** per country and platform, and the **audience targeting** the advertiser used.

![Google Ads Transparency Scraper: Competitor Ad Library - sample output](https://api.apify.com/v2/key-value-stores/QpfrAb6wndEDB0tDd/records/output-5nqFDnFb4qOqaCY5C.png)

**$1.50 per 1,000 ads, with full details included.** No login, no cookies, no Google account, and no proxy fees.

> Independent tool. Not affiliated with, endorsed by or sponsored by Google LLC. It reads only the data Google publishes for ad transparency.

### Why this scraper?

| | Typical ad-library scrapers | **This Actor** |
|---|---|---|
| Price per 1,000 ads | $1.50–$2.00 | **$1.50** |
| Full ad details (every country with dates, EU reach, audience, variations) | extra event, often +$3 per 1,000 | **included, no extra charge** |
| Ad text (headline, description, call to action, landing URL) | missing or a paid add-on | **included** where Google shows it |
| YouTube video link, thumbnail, duration and channel for video ads | preview link only | **included** |
| Proxy | example inputs often use residential proxies | **direct connection first**, then Apify datacenter, then residential only as a last resort, at **no extra cost to you** |
| Ads with problems | silently missing | **free row with the reason** (no ads, unknown advertiser, rate-limited) |
| Spending cap | sometimes overshoots | **stops exactly at your max charge** |

### What you can search

- **Websites (domains):** `nike.com` returns every ad that points at nike.com, from every advertiser account (brand, retailers, agencies).
- **Brand names or keywords:** `HelloFresh` is matched to advertiser accounts with the Transparency Center's own search. The biggest matching account comes first; raise **Advertiser accounts per brand name** to take more. When no account carries the brand's name (Grammarly advertises as "Superhuman Platform Inc."), we use the website Google suggests for the brand (grammarly.com) and say so in `matchedVia`.
- **Advertiser IDs:** `AR16735076323512287233` (from the advertiser page URL).
- **Transparency Center links:** paste advertiser pages, single-ad (creative) pages or domain searches.

Filters: **region** (any country or anywhere), **ad format** (text, image, video), **platforms** (Search, YouTube, Shopping, Maps, Play), **date range**, max ads per target and per run.

### Example input

```json
{
  "domains": ["hellofresh.com"],
  "queries": ["Grammarly"],
  "region": "US",
  "adFormat": "ALL",
  "maxAdsPerTarget": 200
}
```

Only new ads, for a daily competitor watch:

```json
{
  "advertiserIds": ["AR16735076323512287233"],
  "onlyNewAds": true,
  "monitorStoreName": "nike-watch",
  "maxAdsPerTarget": 500
}
```

### Example output (one ad)

```json
{
  "adId": "CR09367480842609229825",
  "advertiserId": "AR05288677867637440513",
  "advertiserName": "Superhuman Platform Inc.",
  "advertiserLegalName": "Superhuman Platform Inc.",
  "advertiserCountry": "US",
  "advertiserVerified": true,
  "format": "VIDEO",
  "firstShown": "2026-07-20T00:00:00Z",
  "lastShown": "2026-10-20T23:17:29Z",
  "daysShown": 92,
  "headline": "Corrigez votre français en temps réel.",
  "description": "Corrigez tous les champs de texte en temps réel.",
  "callToAction": "Télécharger",
  "destinationUrl": "https://www.grammarly.com/fr/a",
  "landingDomain": "grammarly.com",
  "videoUrl": "https://www.youtube.com/watch?v=mPW-BN63M7Y",
  "videoThumbnail": "https://i.ytimg.com/vi/mPW-BN63M7Y/hqdefault.jpg",
  "videoDuration": "0:48",
  "youtubeChannel": "Grammarly",
  "platforms": ["YOUTUBE"],
  "regionCodes": ["FR", "MA"],
  "regions": [
    {"region": "FR", "regionName": "France", "firstShown": "2026-07-20", "lastShown": "2026-10-20",
     "impressionsMin": 0, "impressionsMax": 1000, "platformImpressions": [{"platform": "YOUTUBE", "impressionsMin": 0, "impressionsMax": 1000}]},
    {"region": "MA", "regionName": "Morocco", "firstShown": null, "lastShown": "2026-10-20"}
  ],
  "impressionsMin": 0,
  "impressionsMax": 1000,
  "audienceSelection": {"demographicInfo": "included", "geographicLocations": "included and excluded",
                        "contextualSignals": "included and excluded", "topicsOfInterest": null, "customerLists": "included and excluded"},
  "variationCount": 1,
  "transparencyUrl": "https://adstransparency.google.com/advertiser/AR05288677867637440513/creative/CR09367480842609229825?region=anywhere",
  "status": "ok"
}
```

Field notes:

- **`daysShown`**: how long the ad has been running. Long-running ads are usually the ones that work.
- **`impressionsMin` / `impressionsMax`** and per-country **`regions[].impressions*`**: Google's "times shown" ranges. Google publishes them only for ads shown in the EU (Digital Services Act), so they are empty for ads that never ran there.
- **`audienceSelection`**: whether the advertiser used demographics, locations, contextual signals, topics or customer lists (EU ads).
- **`headline`, `description`, `callToAction`, `destinationUrl`, `adTextLines`**: read from Google's own ad preview (`textSource: "preview"`). Many text ads are archived by Google only as a picture; we read the headline, description and display URL from that picture (`textSource: "ocr_snapshot"`, with `ocrConfidence` and `textQuality`), and the picture itself stays in **`imageUrl`**. Latin-script ads read best; text in other scripts that cannot be read is left out (named in `ocrUnreadableParts`) and the row is marked `textQuality: "low"`.
- **`textAvailable`**: whether the row has ad text. Some local/Maps ads use a headline Google writes on the fly from the landing page; then `headline` is empty, `headlineIsDynamic` is true and `textUnavailableReason` says so (the description is still there).
- **Text ads with no readable text** are kept with their dates, regions and links but get `status: "text_unavailable"` and are **not charged** (switch on `chargeTextAdsWithoutText` to treat them as normal ads).
- **Domain searches** return every advertiser account whose ads point to that website, exactly like the Transparency Center (it says "This domain includes results for multiple advertiser accounts"). Placeholder domains such as example.com really do have thousands of ads from unrelated advertisers; the run summary lists `advertisersFound` per domain.
- **`imageUrl`**: the ad image (or Google's archived picture of a text ad). **`variationImageUrls`** lists every A/B variation.
- **`landingDomain`**: where the ad sends people.

Free rows have `status` set to `no_ads`, `no_advertiser`, `no_new_ads`, `text_unavailable`, `invalid_input`, `error` or `charge_limit_too_low`, with a plain-English `error` or `textUnavailableReason`.

### Pricing

Pay per event:

- **$1.50 per 1,000 ads saved** ($0.0015 per ad). Details, ad text, video links and advertiser info are included.
- A tiny start fee of $0.00005 per run.
- Free: rows for targets with no ads, unknown advertisers, invalid input, rate-limit errors, and ads skipped in monitor mode.

Set **Maximum cost per run** in the run options and the Actor stops exactly there. If the cap is below the price of one ad, you get one free row explaining it and nothing else is charged.

### Reliability and fair use

- Uses the same public endpoints the Transparency Center website uses. No login and no personal data: advertisers are businesses.
- Polite by design: paced requests, automatic slow-down and retry when Google pushes back, then a switch to Apify datacenter proxy. It never solves CAPTCHAs or works around Google's bot checks; if Google keeps refusing, you get a free error row and keep every ad already saved.
- **Residential proxy is a last resort, and free for you.** It is used only when Google rate-limits both the direct connection and Apify datacenter proxy, only for the small data requests (a few KB per ad), and its cost is included in the price. Switch off "Allow residential proxy as a last resort" to never use it. If you turn on Apify Proxy in the input yourself, your choice is used from the first request.

### Good to know

- Google filters by date only for roughly the **last 12 months**. Older windows return nothing; leave the dates empty to get every ad with its first and last shown dates.
- Platform filters apply only to ads shown since 4 September 2023 (Google's rule).
- Google's ad counts (in the run summary as `googleAdCountApprox`) are Google's own rough ranges.
- Brand names can match several accounts (for example a person called "Nike Smith"). For exact results, use the website or the advertiser ID.

### Use cases

- **Competitor ad intelligence:** see every ad a rival runs right now, which ones have run longest, and where.
- **Creative research and swipe files:** headlines, descriptions, images and YouTube videos at scale.
- **Reach and media mix (EU):** compare impressions by country and platform.
- **Monitoring:** schedule a daily run with monitor mode and get only newly launched ads.
- **Lead generation and ad checks:** find which companies advertise on Google and under which legal entity.

### Integrations

Run it from the Apify API, the Python or JavaScript client, schedules, webhooks, Make, Zapier or n8n, and export to JSON, CSV, Excel or Google Sheets.

# Actor input Schema

## `domains` (type: `array`):

Every ad that sends people to these websites, from any advertiser account. Example: nike.com, hellofresh.com.

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

Free text such as "Nike" or "Grammarly". It is matched to advertiser accounts with Google's own Transparency Center search (the biggest matching account first). Domains and AR... IDs typed here work too.

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

IDs that start with AR, from the advertiser's page URL, e.g. AR16735076323512287233.

## `startUrls` (type: `array`):

Paste advertiser, single-ad (creative) or domain-search links copied from adstransparency.google.com.

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

Stop after this many ads for each target. You pay only for ads saved.

## `maxTotalAds` (type: `integer`):

A hard cap across all targets. You can also set a maximum cost per run in the run options.

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

Only ads shown in this country. "Anywhere" returns ads from every country.

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

Google's own format filter.

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

Leave empty for all. Google applies platform filters only to ads shown since 4 Sep 2023.

## `startDate` (type: `string`):

Only ads shown on or after this date (YYYY-MM-DD). Google answers date filters for roughly the last 12 months.

## `endDate` (type: `string`):

Only ads shown on or before this date (YYYY-MM-DD). Empty = today.

## `maxAdvertisersPerQuery` (type: `integer`):

How many matching advertiser accounts to take for each brand name / keyword (biggest first).

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

Every country the ad ran in with dates, EU impressions ranges per country and platform, audience targeting, all variations, and the ad's headline, description, landing page and YouTube video. No extra charge; turn off only for the fastest possible runs.

## `readTextFromSnapshots` (type: `boolean`):

Many search text ads are archived by Google only as a rendered picture (the Transparency Center page shows that picture). We read the headline, description and display URL from it with OCR (textSource = ocr_snapshot, with ocrConfidence). No extra cost.

## `chargeTextAdsWithoutText` (type: `boolean`):

Off (default): a text ad whose text Google did not keep in any readable form is still saved with its dates, regions and links, but with status text_unavailable and NOT charged. Turn on to treat these like normal ads.

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

One small lookup per advertiser, cached for the run.

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

Remembers every ad ID it has saved in a named key-value store, so scheduled runs return (and charge) only new ads.

## `monitorStoreName` (type: `string`):

Use a different name per competitor or schedule so their histories don't mix. Letters, digits and dashes.

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

Leave off for most runs: the scraper connects directly and switches to Apify datacenter proxy automatically if Google slows it down. If you turn Apify Proxy on here, it is used from the start.

## `residentialFallback` (type: `boolean`):

Used only if both the direct connection and Apify datacenter proxy are rate-limited by Google, and only for the small data requests (ad images and previews never go through it). The proxy cost is covered by the Actor's price. Turn off to never use residential IPs.

## Actor input object example

```json
{
  "domains": [
    "nike.com"
  ],
  "maxAdsPerTarget": 20,
  "maxTotalAds": 0,
  "region": "anywhere",
  "adFormat": "ALL",
  "maxAdvertisersPerQuery": 1,
  "includeDetails": true,
  "readTextFromSnapshots": true,
  "chargeTextAdsWithoutText": false,
  "includeAdvertiserInfo": true,
  "onlyNewAds": false,
  "monitorStoreName": "ads-transparency-monitor",
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "residentialFallback": true
}
```

# Actor output Schema

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

One row per ad, plus free rows explaining any target with no ads or an error.

## `summary` (type: `string`):

OUTPUT record: ads saved per target, Google's approximate ad counts, network stats.

# 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 = {
    "domains": [
        "nike.com"
    ],
    "maxAdsPerTarget": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

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

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

```

## MCP server setup

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