Google Ads Transparency Center Scraper
Pricing
Pay per event
Google Ads Transparency Center Scraper
Get the ads an advertiser runs on Google, up to 5,000 per input line. Search by name, ID or domain and filter by region, date, format and platform. Each ad has format, first/last shown, days shown, image or preview URL, text where shown, landing domain. Optional per-region dates and impressions.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Michael Lip
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
12 hours ago
Last modified
Categories
Security
Limited permissionsShare
Get the ads any advertiser runs on Google as clean JSON rows, from $0.0012 per ad, by name, advertiser ID or website domain.
The data comes from the public Google Ads Transparency Center. The Actor reads the same JSON endpoints that page uses, with no browser and no login. In a test run on 2026-11-05 it saved 50 Nike ads with 2 requests to Google.
Use it to see what a competitor is running and for how long, to collect creatives from a whole category, to watch an advertiser on a schedule, or to find resellers and affiliates that send ad traffic to your domain.
What you get
One dataset row per ad. The first group of fields is always there. The second group is filled only when you turn on Include ad details.
| Field | Type | Meaning |
|---|---|---|
advertiserId | string | Google's advertiser ID (AR...) |
advertiserName | string or null | The advertiser's legal name as Google lists it |
creativeId | string | Google's ID of the ad (CR...) |
format | string or null | text, image or video |
firstShown, lastShown | ISO timestamp (UTC) or null | When Google first and last showed the ad. For a running ad, lastShown is recent |
daysShown | number or null | Days the ad was shown, as Google reports it |
landingDomain | string or null | Domain the ad sends traffic to, when Google lists it |
imageUrl, width, height | string, number or null | Image of the ad. Google shows many text ads as an image, so text ads often have one too |
previewUrl | string or null | Google's preview script (content.js) for ads without a direct image, such as most video ads |
headline, description, displayUrl | string or null | Text ad copy, only when Google puts it as plain fields in the preview URL. On real ads this is rare, so expect null most of the time |
adUrl | string | The ad's page in the Ads Transparency Center |
regionFilter, platformFilter | string | The region and platform you searched with |
query, queryType | string | The input line that found the ad, and how it was read (name, id, creative or domain) |
scrapedAt | ISO timestamp | When the row was saved |
regions | array or null | Details only. One entry per region where the ad ran, with region (2-letter code, null for areas smaller than a country), regionId, firstShown, lastShown, impressionsMin, impressionsMax. Google adds first dates and impression ranges mainly for EU regions |
platforms | array or null | Details only. Platforms in Google's reach breakdown, such as SEARCH, SHOPPING, YOUTUBE. Often empty for ads shown only outside the EU |
impressionsMin, impressionsMax | number or null | Details only. Google's total impression range. impressionsMin is null when Google gives only an upper bound such as "up to 1,000" |
variationCount, imageUrls | number, array or null | Details only. Number of creative variations and their image URLs |
detailError | string or null | Details only. Why the detail lookup failed. The ad is still saved and the lookup isn't charged |
The dataset has two views in Console, Ads (with image previews) and Regions and reach.
Each run also writes a report to the key-value store record OUTPUT. It has one entry per input line with the advertiser it resolved to, ads saved, Google's estimate of matching ads (totalEstimate, for example 50000 to 60000 for nike.com) and the error if the line failed.
Example output
This row is real. It comes from run c5A1NgmRygXZXu9Z8 on 2026-11-05 with input nike.com, region anywhere and details off.
{"advertiserId": "AR16735076323512287233","advertiserName": "Nike, Inc.","creativeId": "CR06692121344286392321","format": "text","firstShown": "2023-11-16T21:49:06.000Z","lastShown": "2026-11-05T11:22:35.000Z","daysShown": 885,"landingDomain": "nike.com","imageUrl": "https://tpc.googlesyndication.com/archive/simgad/11274417169112350865","previewUrl": null,"width": 348,"height": 305,"headline": null,"description": null,"displayUrl": null,"adUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR06692121344286392321","regionFilter": "anywhere","platformFilter": "all","query": "nike.com","queryType": "domain","scrapedAt": "2026-11-05T11:40:37.956Z"}
With Include ad details on, each row gets these extra fields. They're from a test run on 2026-11-05 with input nike.com, region DE, for ad CR10056063563010670593 of Nike Retail BV.
{"regions": [{ "region": "NL", "regionId": 2528, "firstShown": "2023-03-12", "lastShown": "2024-02-23", "impressionsMin": null, "impressionsMax": 1000 },{ "region": "PL", "regionId": 2616, "firstShown": "2023-03-01", "lastShown": "2026-11-05", "impressionsMin": 5000000, "impressionsMax": 6000000 }],"platforms": ["SEARCH", "SHOPPING", "YOUTUBE"],"impressionsMin": 5000000,"impressionsMax": 6000000,"variationCount": 3,"imageUrls": [],"detailError": null}
Pricing
You pay per result. There's no subscription and no charge for compute.
| Event | Price | When it's charged |
|---|---|---|
ad | $0.0012 | Each ad row saved, after filters and duplicate removal |
ad-detail | $0.002 | Each successful detail lookup, only with Include ad details on |
Some worked examples.
| Job | Math | Cost |
|---|---|---|
| The prefilled first run (20 ads) | 20 × $0.0012 | $0.024 |
| 1,000 ads | 1,000 × $0.0012 | $1.20 |
| 1,000 ads with details | 1,000 × ($0.0012 + $0.002) | $3.20 |
| 10 competitors, 200 ads each | 2,000 × $0.0012 | $2.40 |
You aren't charged for advertisers that aren't found or fail, for the same ad found by two input lines, for ads your filters drop, or for failed detail lookups. Set a maximum cost per run (maxTotalChargeUsd in the API) and the Actor stops before a row it can't pay for in full, then says so in the run report.
Quick start in Console
- Open the Actor and click Start. The input is prefilled with
nike.com, region US and 20 ads, so the first run costs about $0.02 and takes a few seconds. - Open the Ads view of the dataset, or export it as JSON, CSV or Excel.
- Swap in your own advertisers, one per line, and raise "Max ads per advertiser".
Use it from the API
This call runs the Actor and returns the rows in one response. Sync calls wait up to 300 seconds, so for big jobs start an async run and read the dataset when it finishes.
curl -X POST "https://api.apify.com/v2/acts/zovo-one~google-ads-transparency-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"advertisers": ["nike.com", "AR16735076323512287233"],"region": "US","dateFrom": "90 days","format": "video","maxAdsPerAdvertiser": 100,"includeDetails": false}'
Use it from Python
$pip install apify-client
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("zovo-one/google-ads-transparency-scraper").call(run_input={"advertisers": ["nike.com", "Adidas AG"],"region": "US","maxAdsPerAdvertiser": 100,})for ad in client.dataset(run["defaultDatasetId"]).iterate_items():print(ad["advertiserName"], ad["format"], ad["daysShown"], ad["adUrl"])
Use it from Node.js
$npm install apify-client
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('zovo-one/google-ads-transparency-scraper').call({advertisers: ['nike.com', 'Adidas AG'],region: 'US',maxAdsPerAdvertiser: 100,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.length, items[0]);
Use it from AI agents (MCP)
AI agents can call this Actor as a tool through the Apify MCP server. Each client adds servers in its own way. VS Code and Claude Desktop, for example, don't take the JSON below as written. For your client, open the MCP configurator, pick this Actor and copy the setup it gives you. A client that reads an mcpServers block with a url key, such as Cursor, can use this config.
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=zovo-one/google-ads-transparency-scraper"}}}
On the first connection your browser opens so you can sign in to Apify. To skip that, add the header "Authorization": "Bearer <APIFY_TOKEN>" to the server config.
Without the tools parameter, an agent can still find the Actor with search-actors, run it with call-actor, and read the rows with get-dataset-items.
Here's a prompt that works well.
Use the Google Ads Transparency scraper to get up to 50 video ads that nike.comran in the US in the last 90 days. Sort them by daysShown and tell me which5 ran the longest, with their adUrl.
Input
| Field | What it does | Example |
|---|---|---|
advertisers | Required. One per line, up to 100 advertisers: a name, an advertiser ID (AR...), a domain, or an Ads Transparency Center URL | ["nike.com", "AR16735076323512287233", "Adidas AG"] |
region | 2-letter country code, or anywhere. Default anywhere | "US" |
dateFrom | Only ads shown on or after this date. YYYY-MM-DD or relative (30 days, 3 months) | "90 days" |
dateTo | Only ads shown on or before this date. Needs dateFrom. Empty means today | "2026-06-30" |
format | all, text, image or video. Default all | "video" |
platform | all, SEARCH, YOUTUBE, SHOPPING, MAPS or PLAY. Default all | "YOUTUBE" |
maxAdsPerAdvertiser | Ads to save per input line, 1 to 5,000. Default 50 | 200 |
includeDetails | Adds regions, per-region dates, impression ranges, platforms and creative variations. One extra request per ad, charged as ad-detail. Default off | true |
proxyConfiguration | Apify Proxy is on by default. Pick the RESIDENTIAL group if Google blocks the run | {"useApifyProxy": true} |
maxConcurrency | Advertisers read in parallel, 1 to 3. Default 2 | 2 |
How each kind of input line is read.
- An advertiser ID or a Transparency Center advertiser URL (
https://adstransparency.google.com/advertiser/AR...) reads that advertiser. It's the most precise choice. - A domain (
nike.com,https://www.nike.com/us) returns ads from each advertiser that sends traffic to it. Fornike.comthat's "Nike, Inc." plus Nike's regional companies, and it can include resellers. Unicode domains are sent in their ASCII form. - A name must match an advertiser name exactly, ignoring case, accents, punctuation,
&versusand, a leading "The" and up to two company suffixes such as Inc or GmbH. Sonike incmatches "Nike, Inc.", butCocadoesn't match "Coca-Cola". When several advertisers share the name, the one with the most ads is read and the rest are listed inOUTPUT. When nothing matches, the run report lists the closest names with their IDs. - An ad URL (
.../advertiser/AR.../creative/CR...) saves only that one ad, if it's among the first 400 ads Google lists for that advertiser with your filters.
A line that can't be read is reported in OUTPUT and the other lines still run.
Limits
- Up to 100 advertisers and 1,000 input lines per run. Split bigger lists into several runs.
- Up to 5,000 ads per input line. A domain or advertiser with more matching ads returns the same first 5,000 each time, so narrow the region, format, platform or dates to reach others.
- Google's date filter covers about the last 12 months. A range that ends before that is rejected with an explanation. For older ads, leave the dates empty and use
firstShownandlastShown.
The Actor reads 40 ads per request, spaced at least 0.3 seconds apart with Apify Proxy and 1 second without. Details add one request per ad. A blocked request is retried up to 5 times with a new proxy session.
Two breakers keep a bad run short. After 3 failed detail lookups in a row, the rest of the ads are saved without details. Those rows still cost the ad price, but not ad-detail. After 3 advertisers in a row fail, the run stops and marks the remaining lines as skipped.
Near the run timeout the Actor stops, keeps what it saved and still writes OUTPUT. If the platform restarts a run, ads already saved are skipped and not charged again. Ads aren't remembered between runs, though. For monitoring, drop creativeId values you've already seen on your side.
There's no OCR and no video download. When Google shows a text ad only as an image, the text is in imageUrl. Video ads come with previewUrl.
FAQ
Why did a domain return ads from several advertisers
A domain search returns each advertiser that sends traffic to it. That can be the brand, its regional companies, resellers or affiliates. Filter on advertiserId, or use the advertiser ID as input.
A name wasn't found, but the advertiser exists
Names have to match exactly, apart from case, accents, punctuation and company suffixes. Open the OUTPUT record. It lists the closest names with their IDs, so you can rerun with the ID or the domain.
How do the date filters work
An ad is kept when it was shown at any time in your range. So it ended on or after "Shown since" and started on or before "Shown until". All dates are UTC.
How do I watch a competitor every day
Schedule the Actor in Console with "Shown since" set to 2 days. Each run returns the ads that are new or still running, and you pay only for those rows.
What if Google blocks the run
If no ad was saved yet, the run fails with a clear message and nothing is charged. If the block comes partway through, the ads saved before it are kept and charged, and OUTPUT lists the advertisers that failed. Open the Proxy setting and pick the RESIDENTIAL group, then run it again.
Is this legal
The Actor reads data Google publishes for public transparency, with no login. It collects advertiser names and ads, not data about people. You're responsible for how you use the data and for following Google's terms in your use case. This Actor isn't affiliated with, endorsed by or sponsored by Google.
Support
Open an issue in the Actor's Issues tab with the run ID and your input. The Transparency Center endpoints aren't an official API and Google can change them. When Google answers in a shape the Actor doesn't know, that advertiser gets an error in the run report instead of an empty result, so please report it and it'll get fixed.