# Google Ads Transparency Scraper - Ad Copy, Reach & New Ads (`crawlplant/google-ads-transparency`) Actor

Every Google ad of a domain, advertiser or brand from the Ads Transparency Center: first and last shown, ad copy and landing page (text ads read from their picture too), countries, EU reach and targeting, who paid. Watch mode returns only new and stopped ads. Works as an MCP tool for AI agents.

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

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 - Ad Copy, Reach & New Ads

*Independent tool, not affiliated with, endorsed by or connected to Google. It reads the public Google Ads Transparency
Center (adstransparency.google.com), the ad library Google publishes for every visitor.*

**Every Google ad a competitor runs**, one row per ad: text, image and video ads on Search, YouTube, Shopping, Maps and
Play, with the **advertiser**, **first and last day shown**, **days shown**, whether it is **running now**, and a link to the
ad. Paste **domains, advertiser names, advertiser ids or Transparency Center URLs**, mixed. On request, per ad: **ad copy**
(headline, description, call to action, display URL, landing page), the **YouTube video** of video ads, product and
merchant of shopping ads, **every country it ran in with first and last day**, and for ads shown in the EU **impressions per
country and platform and the kinds of targeting used**, plus **who paid** (agencies and resellers). A **watch mode** returns
only the ads that are **new since your last run** and the ones that **stopped**. Two more modes: a **domain check** (does a
website advertise on Google, how many ads, since when, by whom) and an **advertiser lookup**.

### Why this one

- **Only what changed, on a schedule.** With `onlyNew` each run returns just the ads a competitor launched since the
  previous run, and with `includeStopped` the ones they switched off. The state stays in a key-value store in your own
  account; you pay for the new ads, not for the same 500 ads every day.
- **Where an ad ran and how many people saw it.** Every country with its first and last day shown; for ads shown in the EU
  the impressions per country and per platform (Search, YouTube, Shopping...) and whether demographics, location,
  context, interests or customer lists were used for targeting, as Google discloses them under the Digital Services Act.
- **The words, not just a screenshot.** Headlines, descriptions, calls to action and landing pages of search, video,
  shopping, local and display ads, YouTube video ids with length and channel, and the visible text of display banners.
  Most text ads exist in the Transparency Center only as a picture: the Actor reads their headline, description, display
  URL and sitelinks from that picture, in the language of your region (19 of 19 text ads of canva.com in Germany on
  2026-10-01, umlauts included).
- **The right account for a brand name.** "Nike" finds Nike Retail BV (80,000-90,000 ads) instead of the first suggestion,
  a one-ad "Nike" account: the Actor picks the biggest whole-word match and lists the other accounts in the log. Or ask
  for the domain and get every account that advertises it, agencies included.
- **Long-running ads first.** Ads Google showed for months are the ones that keep paying off for the advertiser: filter by
  `minDaysShown`, sort by `daysShown`, or keep only the ads launched this week (`firstShownFrom`).
- **Fast and light.** 100 ads come in one request: the default run takes about 5 seconds. 1,000 ads of nike.com took
  18 seconds on 2026-09-29.
- **Runs that finish.** A page or an ad that can't be read is retried through another route; what still fails leaves its
  fields empty, the run carries on and its summary says what was missing.

### What can you use it for?

- **Competitor ad monitoring**: a daily list of the ads your competitors launched and stopped, straight to Slack, e-mail or
  Google Sheets.
- **Creative research**: the headlines, descriptions, calls to action and videos that competitors keep running for months.
- **Market and country research**: who advertises in which country, on which Google platform, since when.
- **Lead generation for agencies**: which of 1,000 websites advertise on Google right now, how many ads they run and who
  manages them.
- **Brand protection**: ads that use your domain, run by accounts that aren't yours (resellers, affiliates, impostors).
- **AI agents**: "what did canva.com launch on YouTube this month?" answered from a few rows.

### Quick start

1. Click **Try for free** (or **Start**) with the default input: the 100 most recently shown ads for nike.com, everywhere.
   About 5 seconds; **about $0.10 on the Free plan**.
2. Put your competitors in **Domains, advertisers or Transparency Center URLs**: `competitor.com`, `Competitor Inc`,
   `AR16735076323512287233` or a URL copied from adstransparency.google.com.
3. Pick a country, a format and a platform; turn on **Ad copy** or **Countries, impressions and targeting** if you need them.
4. Download the table as CSV, Excel or JSON, or save the input as a **task** and schedule it with **Only new ads**.

#### Copy to your AI assistant

Paste this into ChatGPT, Claude or any agent so it knows how to use the Actor:

```
crawlplant/google-ads-transparency on Apify: ads from the Google Ads Transparency Center. Input: mode ("ads" default = one
row per ad, most recently shown first; "advertisers" = one row per advertiser account; "domainCheck" = one row per domain:
hasAds, adCountMin/Max, isAdvertisingNow, lastAdShown, advertisers), targets (domains like nike.com, advertiser ids
AR..., advertiser names, or adstransparency.google.com URLs incl. single-ad URLs; default ["nike.com"]). Filters: region
(ISO country code or "anywhere"), format (all|text|image|video), platform (all|search|youtube|shopping|maps|play),
dateFrom/dateTo (shown between; 2026-09-01, yesterday, -30; last ~13 months), firstShownFrom (ads started on/after),
minDaysShown, activeOnly, sortBy (lastShown|firstShown|daysShown). Extras: includeDetails (countries with first/last day,
EU impressions per country/platform, targeting types, variations, paidBy), includeAdContent (headline, description,
callToAction, displayUrl, landingUrl, videoUrl, youtubeChannel, merchant, adTexts; text ads kept as a picture are read
by OCR, copySource "ocr", languages from region or ocrLanguages like ["eng","deu"]). Monitoring: onlyNew (only ads not
returned before for the same target+filters; first run = baseline), includeStopped. maxItems = ads per target (default
100). Output rows: creativeId, advertiserId, advertiserName, format, firstShown, lastShown, daysShown, isActive,
matchedDomain, imageUrl, adUrl, watchStatus, ...
```

### Modes

| Mode | One row per | Reads | Typical use |
|---|---|---|---|
| `ads` (default) | ad (creative) | 1 request per 100 ads; +1 per ad for details, +1 per ad for ad copy | competitor ads, monitoring, creative research |
| `advertisers` | advertiser account | 2 requests per account | find a brand's accounts; who advertises a domain |
| `domainCheck` | domain | 1 request per domain | which websites advertise on Google; lead lists |
| `summary` | competitor (target) | 1 request per 100 ads listed; +copy of the `maxItems` newest | compare competitors' strategy |
| `messages` | message (ads grouped by headline) | 1 request per 100 ads; +copy per ad | which messages a competitor invests in |
| `timeline` | week of the last year, per competitor | 1 request per 100 ads, nothing per ad | when a competitor launched and stopped ads, how many ran |

**Targets** can be mixed in one run:

- a **domain** or website URL: `nike.com`, `https://www.nike.com/us/` (reduced to `nike.com`; the Transparency Center
  indexes the main domain, so `shop.example.co.uk` becomes `example.co.uk`),
- an **advertiser id**: `AR16735076323512287233` (in the address of an advertiser page),
- an **advertiser name**: `Shopify` (the biggest matching account; `advertisersPerName` reads more),
- a **Transparency Center URL**: an advertiser page, a single ad (`/advertiser/AR.../creative/CR...`) or a domain search
  (`/?domain=nike.com`). The URL's own region, format, platform and dates are used for that target.

### Ready-to-use examples

**1. The latest ads of a competitor's domain**

```json
{ "targets": ["nike.com"], "maxItems": 100 }
```

**2. A competitor's YouTube video ads in the UK, with the video and the copy**

```json
{ "targets": ["canva.com"], "region": "GB", "format": "video", "includeAdContent": true, "maxItems": 50 }
```

**3. Search ad copy: headlines, descriptions and display URLs**

```json
{ "targets": ["booking.com"], "format": "text", "platform": "search", "includeAdContent": true, "maxItems": 100 }
```

**4. A brand by name (the biggest matching account)**

```json
{ "targets": ["Shopify"], "maxItems": 200 }
```

**5. Advertiser ids and Transparency Center URLs, mixed**

```json
{
  "targets": [
    "AR16735076323512287233",
    "https://adstransparency.google.com/advertiser/AR13289988016354361345?region=US&format=VIDEO"
  ],
  "maxItems": 100
}
```

**6. Where each ad ran, EU impressions and targeting**

```json
{ "targets": ["zalando.de"], "region": "DE", "includeDetails": true, "maxItems": 100 }
```

**7. The longest-running ads that are still live**

```json
{ "targets": ["hubspot.com"], "minDaysShown": 90, "activeOnly": true, "sortBy": "daysShown", "maxItems": 50 }
```

**8. Ads launched in the last 7 days**

```json
{ "targets": ["temu.com"], "firstShownFrom": "-7", "sortBy": "firstShown", "maxItems": 100, "maxScanPages": 30 }
```

**9. Ads shown in the US during the first half of September**

```json
{ "targets": ["nike.com"], "region": "US", "dateFrom": "2026-09-01", "dateTo": "2026-09-15", "maxItems": 500 }
```

**10. Daily watch: new and stopped ads of three competitors, with copy**

```json
{
  "targets": ["canva.com", "adobe.com", "figma.com"],
  "onlyNew": true,
  "includeStopped": true,
  "includeAdContent": true,
  "maxItems": 500
}
```

**11. One ad by its URL, with every detail**

```json
{
  "targets": ["https://adstransparency.google.com/advertiser/AR18378488041124659201/creative/CR14738787052023709697?region=DE"],
  "includeAdContent": true
}
```

**12. Which of these websites advertise on Google?**

```json
{ "mode": "domainCheck", "targets": ["nike.com", "hubspot.com", "notion.so", "example.com"] }
```

**13. Which of them advertise in Germany?**

```json
{ "mode": "domainCheck", "targets": ["nike.com", "hubspot.com", "notion.so"], "region": "DE" }
```

**14. Every Google Ads account of a brand**

```json
{ "mode": "advertisers", "targets": ["Canva"], "maxItems": 20 }
```

**15. Everyone advertising a domain: the brand, agencies, resellers**

```json
{ "mode": "advertisers", "targets": ["hubspot.com"], "maxItems": 50 }
```

**16. Compare competitors in one table: running and new ads, top messages, landing pages, campaigns**

```json
{ "mode": "summary", "targets": ["canva.com", "figma.com", "miro.com"], "region": "US", "maxItems": 100 }
```

**17. A competitor's messages, most used and longest running first**

```json
{ "mode": "messages", "targets": ["semrush.com"], "region": "US", "maxItems": 200 }
```

**18. A competitor's year of Google Ads, week by week**

```json
{ "mode": "timeline", "targets": ["figma.com", "miro.com"] }
```

### How to…

#### See when a competitor launched and stopped its Google ads

`mode: "timeline"` (example 18) gives 52 rows per competitor, one per week of the last year: ads launched (by format),
ads stopped, ads shown and ads running on an average day. It reads the whole ad list (100 ads per request, nothing per
ad), so a year of a big advertiser costs a few cents and takes seconds: figma.com and miro.com together, 104 rows, 98
requests on 2026-10-01. figma.com launched 450 ads in the week of 2026-02-23: from ~130 ads running on an average day in late January to ~490. Ads
often pause between their first and last day (47% of miro.com's): `avgRunningAds` counts each ad in proportion to the
days it was really shown, `adsShown` is every ad whose run touches the week.

#### Compare competitors' Google Ads strategy

`mode: "summary"` (example 16) gives one row per competitor. It counts from the ad list: ads running now, ads launched
in the last 7 and 30 days, formats, the median number of days an ad runs and which accounts run them. It reads the
copy of the `maxItems` most recently shown ads for the top messages, longest-running ads, top landing pages and top
campaigns (the `utm_campaign` tags of the landing URLs). For a domain, accounts that only link to it now and then are
left out of the figures (`adsFromOtherAdvertisers`); accounts named after the brand and agencies running its ads stay.
On 2026-10-01, canva.com in the US: 1,449 ads listed, 1,363 running, 420 launched in the last 30 days, top campaign
`us_en_all_payback_generic_lower_rev_demand-gen_youtube`.

#### See which messages a competitor invests in

`mode: "messages"` (example 17) groups the ads by message (the headline, or the first line of text) and ranks them by
number of ads, then by the longest run: the messages a competitor keeps paying for come first, each with its ads
running now, days shown, landing pages and campaigns.

#### See a competitor's campaign structure

Every ad row with copy carries `landingPage` and the URL's campaign tags `utmCampaign`, `utmSource`, `utmMedium`,
`utmContent` and `utmTerm`. Advertisers name campaigns by market, language, goal and channel
(`uk_en_all_mau_generic_mid_acq_demand-gen_youtube`), so they show how the account is organised.

#### Get every Google ad a competitor runs

Put the competitor's domain in `targets` (example 1). The domain search finds the ads of **every account** that
advertises that domain: the brand's regional accounts, its agencies and resellers (`advertiserName`, `matchedDomain`).
Raise `maxItems` to go deeper; ads come most recently shown first, 100 per request.

#### Monitor a competitor's new Google ads every day

Save example 10 as a task and schedule it daily. The first run returns the current ads (`watchStatus: "baseline"`);
every later run returns only ads not returned before (`"new"`) and, with `includeStopped`, ads that were running at the
previous run and aren't any more (`"stopped"`). Connect Slack, e-mail or Google Sheets to the task's dataset.

#### See where a Google ad ran and how many people saw it

Turn on `includeDetails` (example 6): `countries` lists every country the ad was shown in, `countryReach` adds the first and
last day per country, and for ads shown in the EU the impressions per country and per platform. `euImpressionsMin` /
`euImpressionsMax` is the EU total as Google publishes it (a range, e.g. 10,000-15,000).

#### Get competitors' Google ad copy and landing pages

Turn on `includeAdContent` (examples 2, 3, 10): `headline`, `longHeadline`, `description`, `callToAction`, `displayUrl`
and `landingUrl` where the ad has them; shopping ads give the product title and `merchant`; display banners give their
visible text in `adTexts` and their images in `adImageUrls`. Text ads kept as a picture are read from the picture
(`copySource: "ocr"`): headline, description, display URL, and the sitelinks in `adTexts`.

#### Download a competitor's YouTube ads

`format: "video"` (or `platform: "youtube"`) with `includeAdContent` gives `videoUrl` (youtube.com/watch?v=...), `videoId`,
`videoDuration` and `youtubeChannel` for each video ad.

#### Find a competitor's winning (long-running) Google ads

Advertisers switch off ads that don't work. `minDaysShown: 90` with `activeOnly: true` and `sortBy: "daysShown"` (example 7)
lists the ads that have been running for months and still are.

#### Check which websites advertise on Google

`mode: "domainCheck"` (examples 12 and 13): one row per domain with `hasAds`, `isAdvertisingNow`, the ad count range, the
last day an ad was shown, the newest ad's start, the advertisers behind it and the formats of its recent ads. One request
per domain, so a list of 1,000 domains takes a few minutes.

#### Find all Google Ads accounts of a brand

`mode: "advertisers"` with a name (example 14) lists every matching account, biggest first, with its legal name, billing
country, verification and ad count; with a domain (example 15) it lists everyone who advertises that domain.

### Input options

| Option | Default | What it does |
|---|---|---|
| `mode` | `ads` | `ads`, `advertisers` or `domainCheck` (see Modes). |
| `targets` | `["nike.com"]` | Domains, advertiser ids, advertiser names, Transparency Center URLs. |
| `region` | `anywhere` | Only ads shown in this country (2-letter code: US, GB, DE, FR, AU, ... 244 countries and territories). |
| `format` | `all` | `text`, `image` or `video`. |
| `platform` | `all` | `search`, `youtube`, `shopping`, `maps` or `play`. |
| `dateFrom`, `dateTo` | empty | Only ads shown between these days (`2026-09-01`, `yesterday`, `-30`). About the last 13 months. |
| `firstShownFrom` | empty | Only ads that started on or after this day. |
| `minDaysShown` | 0 | Only ads shown on at least this many days. |
| `activeOnly` | false | Only ads shown in the last 2 days. |
| `sortBy` | `lastShown` | `lastShown` (the site's order), `firstShown` (newest ads first), `daysShown` (longest running first). |
| `includeDetails` | false | Countries, first/last day per country, EU impressions and targeting, variations, who paid. +1 request per ad. |
| `includeAdContent` | false | Headline, description, call to action, landing page, YouTube video, merchant, visible text. +1 request per ad. |
| `ocrTextAds` | true | With `includeAdContent`: read headline, description, display URL and sitelinks of text ads that Google keeps only as a picture. |
| `ocrLanguages` | empty | Languages of that text (`eng`, `deu`, `fra`, `spa`, `pol`, `jpn`...); empty = English plus the language of `region`. |
| `onlyNew` | false | Watch mode: only ads not returned before for the same target and filters. |
| `includeStopped` | false | With watch mode: also ads that stopped running since the previous run. |
| `advertisersPerName` | 1 | Ads mode, advertiser names: how many matching accounts to read. |
| `maxItems` | 100 | Ads per target (watch mode: how many of the latest ads each run compares); advertisers mode: accounts per target; summary and messages modes: ads read with their copy per target. |
| `maxScanPages` | 20 | Pages (100 ads each) read per target when a filter (`minDaysShown`, `firstShownFrom`, `activeOnly`) keeps few ads. |

The country, format, platform and date filters are applied by the Transparency Center itself, so they cost nothing
extra. `minDaysShown`, `firstShownFrom` and `activeOnly` are checked on the ads read; you pay only for the rows returned.

### Example output

One video ad with `includeDetails` and `includeAdContent` (run on 2026-09-29; long URLs shortened):

```json
{
  "recordType": "ad",
  "creativeId": "CR08146901164865093633",
  "advertiserId": "AR01625195283841286145",
  "advertiserName": "Shopify Inc.",
  "isAdvertiserVerified": true,
  "format": "video",
  "firstShown": "2026-08-31T18:01:19.000Z",
  "lastShown": "2026-09-29T22:17:41.000Z",
  "daysShown": 30,
  "runDays": 30,
  "isActive": true,
  "matchedDomain": "shopify.com",
  "imageUrl": null,
  "previewUrl": "https://displayads-formats.googleusercontent.com/ads/preview/content.js?client=ads-integrity-transparency&...",
  "adUrl": "https://adstransparency.google.com/advertiser/AR01625195283841286145/creative/CR08146901164865093633?region=GB",
  "advertiserUrl": "https://adstransparency.google.com/advertiser/AR01625195283841286145?region=GB",
  "countries": ["GB", "IE"],
  "countryReach": [
    { "countryCode": "GB", "country": "United Kingdom", "impressionsMin": null, "impressionsMax": null, "firstShown": null, "lastShown": "2026-09-29", "platforms": [] },
    { "countryCode": "IE", "country": "Ireland", "impressionsMin": null, "impressionsMax": null, "firstShown": "2026-08-31", "lastShown": "2026-09-29", "platforms": [] }
  ],
  "euImpressionsMin": null,
  "euImpressionsMax": null,
  "euFirstShown": "2026-08-31",
  "euLastShown": "2026-09-29",
  "targeting": {
    "included": ["demographics", "geography", "contextual", "customer-lists"],
    "excluded": ["contextual", "customer-lists"],
    "ageRanges": [], "excludedAgeRanges": [], "genders": [], "excludedGenders": [], "locations": [], "excludedLocations": []
  },
  "targetingTypes": ["demographics", "geography", "contextual", "customer-lists", "exclude:contextual", "exclude:customer-lists"],
  "variations": [{ "kind": "script", "previewUrl": "https://displayads-formats.googleusercontent.com/ads/preview/content.js?...", "imageUrl": null, "width": null, "height": null }],
  "variationCount": 4,
  "paidBy": null,
  "containsSyntheticMedia": null,
  "headline": "Launch your brand on Shopify",
  "longHeadline": "The entrepreneur life is calling. Launch your brand on Shopify.",
  "description": "Build the business and life you've always wanted on Shopify. Start for free.",
  "callToAction": null,
  "displayUrl": "shopify.com",
  "landingUrl": "https://shopify.com/free-trial",
  "merchant": null,
  "videoId": "HHQgF6hBHO0",
  "videoUrl": "https://www.youtube.com/watch?v=HHQgF6hBHO0",
  "videoDuration": "0:15",
  "youtubeChannel": "Shopify",
  "adImageUrls": [],
  "adTexts": [],
  "watchStatus": null,
  "firstSeenAt": null,
  "target": "https://adstransparency.google.com/?region=GB&domain=shopify.com&format=VIDEO",
  "targetType": "domain",
  "region": "GB",
  "scrapedAt": "2026-09-29T22:41:34.368Z",
  "source": "live",
  "store": "google-ads-transparency"
}
```

A `domainCheck` row (nike.com in Germany, 2026-09-29):

```json
{
  "recordType": "domainCheck",
  "domain": "nike.com",
  "hasAds": true,
  "adCountMin": 20000,
  "adCountMax": 30000,
  "isAdvertisingNow": true,
  "lastAdShown": "2026-09-29T22:19:14.000Z",
  "newestAdFirstShown": "2026-07-30T15:50:40.000Z",
  "advertiserCount": 5,
  "topAdvertiser": "Nike Retail BV",
  "recentFormats": { "text": 95, "image": 0, "video": 5 },
  "recentAdsRead": 100,
  "domainUrl": "https://adstransparency.google.com/?region=DE&domain=nike.com"
}
```

### Output fields

Ad rows (`recordType: "ad"`):

| Field | Meaning |
|---|---|
| `creativeId`, `advertiserId` | Google's ids of the ad and the advertiser account (stable). |
| `advertiserName`, `isAdvertiserVerified` | The account's name and whether Google verified it. |
| `format` | `text`, `image` or `video`. |
| `firstShown`, `lastShown` | First and most recent time the ad was shown (UTC). |
| `daysShown` | Days the ad was shown, as Google counts them. `runDays`: calendar days from first to last shown. |
| `isActive` | Shown in the last 2 days. |
| `matchedDomain` | The advertised domain. |
| `imageUrl`, `imageWidth`, `imageHeight` | A picture of the ad, when Google archives it as one (most text ads, many image ads). |
| `previewUrl` | Google's interactive preview of the ad (a script the Transparency Center renders). |
| `adUrl`, `advertiserUrl` | The ad's and the advertiser's pages in the Transparency Center. |
| `countries`, `countryReach` | With `includeDetails`: countries shown in; per country the first and last day, impressions (EU), platforms. |
| `euImpressionsMin/Max`, `euFirstShown`, `euLastShown` | With `includeDetails`: EU total, for ads shown in the EU. |
| `targeting`, `targetingTypes` | With `includeDetails`, EU ads: kinds of targeting used to include or exclude people. |
| `variations`, `variationCount` | With `includeDetails`: every version of the ad (sizes, headlines, assets). |
| `paidBy` | With `includeDetails`: who paid for the ad, when Google names them (often an agency). |
| `headline`, `longHeadline`, `description`, `callToAction`, `displayUrl`, `landingUrl` | With `includeAdContent`, when the ad has them. |
| `videoId`, `videoUrl`, `videoDuration`, `youtubeChannel` | With `includeAdContent`: video ads. |
| `merchant`, `adImageUrls`, `adTexts` | With `includeAdContent`: shopping merchant, images in the ad, every line of text in the ad (sitelinks included). |
| `landingPage`, `utmCampaign`, `utmSource`, `utmMedium`, `utmContent`, `utmTerm` | With ad copy: the landing URL without its query and its campaign tags. |
| `copySource` | `preview` (read from the ad itself) or `ocr` (read from the picture of a text ad); empty without copy. |
| `watchStatus`, `firstSeenAt` | With `onlyNew`: `baseline`, `new` or `stopped`, and when the watch first saw the ad. |
| `target`, `targetType`, `region` | Which target and country filter the row came from. |
| `scrapedAt`, `source`, `store` | When it was read (always live). |

Advertiser rows (`recordType: "advertiser"`): `advertiserId`, `advertiserName`, `legalName`, `country` (billing country),
`isVerified`, `adCountMin` / `adCountMax` (with the region, format and platform filters), `lastAdShown`,
`adsForDomainMin` / `adsForDomainMax` (domain targets: this account's ads for that domain), `nameHistory`, `advertiserUrl`.

Domain rows (`recordType: "domainCheck"`): `domain`, `hasAds`, `isAdvertisingNow`, `adCountMin` / `adCountMax`,
`lastAdShown`, `newestAdFirstShown`, `advertiserCount`, `topAdvertiser`, `advertisers` (id, name, `recentAds` among the
100 most recent), `recentFormats`, `recentAdsRead`, `domainUrl`.

Summary rows (`recordType: "summary"`): `adCountMin` / `adCountMax`, `adsListed`, `coversAllRunningAds`, `activeAds`,
`newAds7d`, `newAds30d`, `formats`, `medianDaysShown`, `advertisers`, `adsFromOtherAdvertisers`, `adsAnalyzed`,
`messageCount`, `topMessage` / `topMessages`, `longestRunning`, `topLandingPage` / `topLandingPages`, `topCampaign` /
`topCampaigns`, `topCountries` (with `includeDetails`), `adsWithoutText`.

Week rows (`recordType: "week"`): `week` (Monday), `partialWeek`, `launched`, `launchedByFormat`, `stopped`, `adsShown`,
`avgRunningAds`, `complete` (the whole list was read).

Message rows (`recordType: "message"`): `rank`, `headline`, `description`, `adCount`, `activeAds`, `formats`, `firstShown`,
`lastShown`, `maxDaysShown`, `totalDaysShown`, `landingPages`, `utmCampaigns`, `imageUrl`, `adUrls`.

The Transparency Center gives ad counts and impressions as ranges (e.g. 10,000-20,000); both ends are returned.

### Alerts and scheduling

- **Daily competitor digest**: schedule example 10 every morning and send the dataset to Slack or e-mail with an Apify
  integration. Empty days cost only the run start.
- **Weekly creative review**: example 7 on Mondays into Google Sheets.
- **Lead list refresh**: example 12 monthly with your prospect domains; filter `isAdvertisingNow`.
- **Webhooks**: add a webhook on "run succeeded" to push new ads into your own system.

### Run it through the API

JavaScript:

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('crawlplant/google-ads-transparency').call({ targets: ['canva.com'], format: 'video', includeAdContent: true });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const ad of items) console.log(ad.advertiserName, ad.headline, ad.videoUrl, ad.firstShown);
```

Python:

```python
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("crawlplant/google-ads-transparency").call(run_input={"mode": "domainCheck", "targets": ["nike.com", "notion.so"]})
for d in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(d["domain"], d["hasAds"], d["adCountMin"], d["topAdvertiser"])
```

### Use with AI agents

Add the Actor as a tool through Apify's MCP server: `https://mcp.apify.com?tools=crawlplant/google-ads-transparency`. An
agent can pass a competitor's domain and read what it advertises, where and since when; watch mode fits agents that run
on a schedule ("what's new since yesterday?"). Flat field names and plain values (ISO dates, country codes, numbers) are
easy to quote or store for retrieval.

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

Pay per result: platform usage is included.

| Event | Free plan | Starter | Scale | Business and up |
|---|---|---|---|---|
| Event | Free plan | Starter | Scale | Business and up |
|---|---|---|---|---|
| Ad (per 1,000) | $1.00 | $0.90 | $0.80 | $0.70 |
| Advertiser account (per 1,000) | $3.00 | $2.70 | $2.40 | $2.10 |
| Domain check (per 1,000) | $3.00 | $2.70 | $2.40 | $2.10 |
| Ad analysed in summary or messages mode, copy and OCR included (per 1,000) | $2.00 | $1.80 | $1.60 | $1.40 |
| Week of a competitor timeline (per 1,000 rows; 52 rows per competitor) | $2.00 | $1.80 | $1.60 | $1.40 |
| Extra for an ad: countries, EU impressions and targeting (per 1,000 ads) | $0.50 | $0.45 | $0.40 | $0.35 |
| Extra for an ad: ad copy read from the ad (per 1,000 ads that returned copy) | $1.00 | $0.90 | $0.80 | $0.70 |
| Extra for an ad: text ad copy read from its picture (per 1,000 ads that returned text) | $1.50 | $1.35 | $1.20 | $1.05 |
| Extra for an ad: new in watch mode (per 1,000 new ads) | $1.00 | $0.90 | $0.80 | $0.70 |
| Actor start (per run) | $0.00005 | $0.00005 | $0.00005 | $0.00005 |

An ad's extras are charged only when you turn them on and the ad has them. The baseline run of a watch and stopped-ad
rows pay the ad price only. In summary and messages modes you pay per ad analysed (`maxItems` per target, copy and OCR
included); the summary and message rows and the list counts are free.

| Example on the Free plan | Rows | Cost |
|---|---|---|
| Default run: 100 ads of nike.com | 100 | ~$0.10 |
| 1,000 ads of a domain | 1,000 | ~$1.00 |
| 100 ads with countries, EU impressions and ad copy | 100 | ~$0.30 |
| Daily watch of 3 competitors, ~20 new ads a day with copy | ~600 a month | ~$2.00 a month |
| 1,000 domains checked | 1,000 | ~$3.00 |
| 20 advertiser accounts of a brand | 20 | ~$0.06 |
| Summary of 3 competitors, 100 ads analysed each | 3 | ~$0.60 |
| A year's timeline of one competitor | 52 | ~$0.10 |

Set a **maximum cost per run** in the run options to stop a large run at your budget.

Other Google Ads Transparency Actors on the Apify Store, Free-plan prices read from the Store on 2026-09-29:

| Actor | Users (30 days) | Price |
|---|---|---|
| scrapesage/google-ads-transparency-scraper | 723 | $2.00 / 1,000 ads; full creative detail +$3.00 / 1,000; advertiser $3.00 / 1,000 |
| solidcode/ads-transparency-scraper | 519 | $1.50 / 1,000 ads (from $0.80 on higher plans) + $0.001 per run |
| s-r/google-ads-transparency | 179 | $1.50 / 1,000 ads + $0.00005 per run |
| pulsedata/google-ads-transparency-scraper | 36 | $1.00 / 1,000 ads |
| domestic\_buffalograss/google-ads-transparency-scraper | 21 | $1.00 / 1,000 ads + $0.01 per run; detail +$2.00 / 1,000; OCR text +$2.00 / 1,000 |
| alkausari\_mujahid/google-ads-transparency-scraper (domain check) | 52 | $12.00 / 1,000 domains |
| **This Actor** | new | $1.00 / 1,000 ads; countries and EU reach +$0.50; ad copy +$1.00 (text ads from their picture +$1.50); domain check $3.00 / 1,000 |

### Reliability

- Requests are spaced at a polite pace. When the Transparency Center refuses an address anyway, that address rests and
  the next request goes out from a fresh one, so large runs with details keep going. An ad whose details or copy still
  can't be read keeps every other field, with the missing part empty and not charged.
- The run always finishes: it stops starting new requests shortly before the time limit and saves what it has.
- Every run writes a summary to the key-value store (`OUTPUT`): rows saved, requests, data read, warnings (targets that
  matched nothing, names without an advertiser, filters that kept nothing) and the events charged.

### Data freshness

Every run reads the Transparency Center at that moment. `lastShown` moves within the hour while an ad runs, so
`isActive` and the watch mode see today's activity. Day-by-day activity (the date filter) covers about the last 13
months; the ads themselves go back years (still-running ads first shown in 2021 in our test runs).

### Troubleshooting

- **Fewer ads than expected**: `maxItems` is per target (default 100); filters combine. `minDaysShown`, `firstShownFrom` and
  `activeOnly` are checked on up to `maxScanPages` pages: raise it for very selective filters.
- **No ads for a domain**: use the main domain (`example.com`, not `shop.example.com`); some advertisers show a different
  domain in their ads. Try the brand name or `mode: "advertisers"` with the domain to see who advertises it.
- **A name found the wrong account**: the log lists the matching accounts; use the advertiser id (`AR...`) from the
  advertiser page, or raise `advertisersPerName`.
- **Odd letters in a text ad's copy** (`copySource: "ocr"`): set `region` to the ads' country, or list their languages
  in `ocrLanguages` (`["eng", "deu"]`). The picture itself is in `imageUrl`.
- **No impressions or targeting**: Google publishes them for ads shown in the EU (and for political ads); other ads have
  countries and dates.
- **A watch run returned nothing**: no new ads since the last run. Changing the targets' filters starts a new watch
  (baseline).

### FAQ

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

About $0.10 for the default run of 100 ads and $1.00 per 1,000 ads; details and ad copy are optional extras. See [the
price table](#how-much-does-it-cost-to-scrape-the-google-ads-transparency-center).

#### Is there an official Google Ads Transparency Center API?

Google offers no API for commercial ads in the Transparency Center (only a BigQuery dataset of political ads). This Actor
gives you the same data as the website, as JSON, CSV or Excel, and through the Apify API.

#### Can I see how much a competitor spends on Google Ads?

Google does not publish spend for commercial ads. You get the number of ads, how long each one ran, where, on which
platforms, and for ads shown in the EU the impressions per country: the best public proxy for effort and budget.

#### How do I track when a competitor launches new ads?

Schedule the Actor with `onlyNew: true` (example 10). Each run returns only the ads launched since the previous run, and
`includeStopped` adds the ones they switched off.

#### Which ads are included?

Everything the Transparency Center shows for commercial advertisers: Search, YouTube, Shopping, Maps and Play ads, in text,
image and video formats. Political ads are not the target of this Actor.

#### How far back does it go?

Ads keep their first-shown date however old it is (ads running since 2021 in our test runs); the date filter works on
about the last 13 months of daily activity.

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

The Actor reads public pages that Google publishes for transparency, without logging in, at a polite pace. Advertiser
names can be names of people (sole traders); how you store and use the data is your responsibility under your local law
(e.g. GDPR, CCPA) and Google's terms.

### Limits

- 100 ads per request; ad counts and impressions come as ranges.
- Ad copy depends on the ad's template: search, video, shopping and local ads give headline and description; display
  banners give visible text and images; text ads kept as a picture give headline, description and sitelinks read from it.
- Impressions and targeting: ads shown in the EU only. Spend: not published for commercial ads.
- Details and ad copy: about 3-4 ads per second.
- Watch mode compares the `maxItems` most recently shown ads per target; for advertisers with thousands of running ads,
  raise `maxItems` (only new ads are charged). Up to 10,000 ads are remembered per watch.

### Run summary

Every run stores `OUTPUT` in its key-value store: `itemsPushed`, `warnings`, `charged` (events per type), requests and
data read, and which route answered.

### Privacy

The data is what Google publishes about advertisers: account names (companies, and sometimes people who advertise as
individuals), ids, countries, and their ads. No logins, no personal data of viewers. Each run sends the developer anonymous
feature-usage statistics (the mode and which options were used, never your targets); your Apify account id is replaced
by a one-way hash on arrival.

# Actor input Schema

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

ads = one row per ad (creative) of each target, newest shown first; advertisers = one row per advertiser account (for a name: every matching account, biggest first; for a domain: every account advertising it, including agencies and resellers); domainCheck = one row per domain: does it run Google ads, how many, since when, by whom; summary = one row per target: active and new ads, formats, top messages, longest-running ads, top landing pages and campaigns of its most recently shown ads; messages = the target's ads grouped by message (headline), most used first, with ads, days shown, landing pages and campaigns. summary and messages read every ad's copy and are charged per ad analysed. timeline = one row per week of the last year for each target: ads launched, stopped, shown and running on an average day, from the ad list alone.

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

Mix freely: a domain (nike.com; website URLs and www. are reduced to the domain), an advertiser id (AR16735076323512287233), an advertiser name (Nike, the biggest matching account is used), or a URL copied from adstransparency.google.com (an advertiser page, a single ad, or a search with ?domain=; its region, format, platform and date filters are applied).

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

Only ads shown in this country: a 2-letter code (US, GB, DE, FR, AU, ...) or anywhere. 244 countries and territories.

## `format` (type: `string`):

text = search ads, image = display and shopping ads, video = YouTube and video ads.

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

Only ads shown on this Google platform.

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

Only ads shown on or after this day: 2026-09-01, yesterday, or -30 (30 days ago). The Transparency Center keeps day-by-day activity for about the last 13 months. Empty = any time.

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

Only ads shown on or before this day (same formats). Empty = today.

## `firstShownFrom` (type: `string`):

Only ads that started running on or after this day, e.g. -7 for ads launched in the last week. Checked on the ads read (see Max ads per target).

## `minDaysShown` (type: `integer`):

Only ads Google showed on at least this many days. Long-running ads are the ones that keep paying off for the advertiser. 0 = any.

## `activeOnly` (type: `boolean`):

Only ads shown in the last 2 days.

## `sortBy` (type: `string`):

lastShown = the Transparency Center's own order (most recently shown first); firstShown = newest ads first; daysShown = longest-running first. The last two sort the ads read (Max ads per target).

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

One extra request per ad: every country the ad was shown in with its first and last day; for ads shown in the EU also impressions per country and per platform and the kinds of targeting used (Digital Services Act disclosures); all variations of the ad; who paid for it. Charged per ad as ad-details.

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

One extra request per ad: headline, description, call to action, display URL and landing page when the ad has them, the YouTube video id and duration of video ads, product title and merchant of shopping ads, the visible text of display ads. Charged per ad that returned copy as ad-content.

## `ocrTextAds` (type: `boolean`):

With ad copy on: Google keeps most text ads only as a picture of the ad. This reads the headline, description, display URL and sitelinks from that picture. Charged per ad that returned text as ad-text-ocr.

## `ocrLanguages` (type: `array`):

Languages of the ads' text for the OCR, as Tesseract codes: eng, deu, fra, spa, ita, por, nld, pol, tur, jpn, kor, chi\_sim... (up to 5). Empty = English plus the language of the chosen region.

## `onlyNew` (type: `boolean`):

Watch mode for scheduled runs: returns only ads this Actor has not returned before for the same target and filters. The first run returns the current ads as the baseline. The state is kept in a key-value store named google-ads-transparency-watch in your own account. Each run compares the Max ads per target most recently shown ads.

## `includeStopped` (type: `boolean`):

With watch mode: also returns ads that were running at the previous run and are not running any more (watchStatus stopped).

## `advertisersPerName` (type: `integer`):

Ads mode, for advertiser names: how many matching accounts to read (biggest first). Brands often have one account per country or agency; the log lists the others.

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

Ads mode: rows per target (in watch mode: how many of the most recently shown ads each run compares). Advertisers mode: accounts per name or domain. Summary and messages modes: how many of the most recently shown ads to analyse per target (200-500 gives a fuller picture).

## `maxScanPages` (type: `integer`):

Safety cap on pages read per target (100 ads per page) when selective filters (minimum days shown, first shown from, running now) keep few of the ads read. Never fewer pages than Max ads per target needs.

## Actor input object example

```json
{
  "mode": "ads",
  "targets": [
    "nike.com"
  ],
  "region": "anywhere",
  "format": "all",
  "platform": "all",
  "minDaysShown": 0,
  "activeOnly": false,
  "sortBy": "lastShown",
  "includeDetails": false,
  "includeAdContent": false,
  "ocrTextAds": true,
  "ocrLanguages": [],
  "onlyNew": false,
  "includeStopped": false,
  "advertisersPerName": 1,
  "maxItems": 100,
  "maxScanPages": 20
}
```

# Actor output Schema

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

No description

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

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlplant/google-ads-transparency").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("crawlplant/google-ads-transparency").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 '{}' |
apify call crawlplant/google-ads-transparency --silent --output-dataset

```

## MCP server setup

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

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/Nvgo4YeUn4C1yDbfN/builds/EjZKugWFr473M4TbC/openapi.json
