Google Ads Transparency Scraper & Change Monitor
Pricing
from $2.00 / 1,000 returned ads
Google Ads Transparency Scraper & Change Monitor
Extract every live Google ad creative for any advertiser: image, video and text, with real asset URLs and first/last-seen dates. See what a competitor launched and stopped since your last run. Domain search catches every ad account, incl. agencies. A zero-ad run is never silent: the log says why.
Pricing
from $2.00 / 1,000 returned ads
Rating
0.0
(0)
Developer
Bujar K
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
What does Google Ads Transparency Scraper & Change Monitor do?
Google Ads Transparency Scraper extracts every ad creative an advertiser is currently running on Google — image, video and text — straight from the Google Ads Transparency Centre. You get the real creative asset URLs, the advertiser account behind each ad, first-seen and last-seen dates, and the country each ad runs in. Search by domain (nike.com) or by brand name, pick a country, and run it. Because it runs on the Apify platform you also get a REST API, scheduling, webhooks, monitoring, and integrations with Make, Zapier, n8n and Google Sheets.
Try it with the default input — it returns about 55 ads from two advertisers in about five seconds. The pair is deliberate: nike.com is enormous, so you see how the Actor behaves when an inventory is bigger than your limit, and brewdog.com is small enough to scan completely — run it a second time and you will see the change monitor label real launches and pauses.
Why use Google Ads Transparency Scraper?
Google publishes this data because the EU Digital Services Act requires it. That makes it one of the few genuinely public windows into what your competitors are spending money on right now.
- See competitors' live creative. Which headlines, images and videos are running today, not last quarter.
- Build a creative swipe file. Every asset URL, ready to download.
- Track launches and seasonality. First-seen and last-seen dates show exactly when a campaign started and whether it is still live.
- Monitor brand and trademark abuse. Find resellers and affiliates bidding on your brand.
- Feed an ad-intelligence product. Stable JSON, incremental runs, and an API — designed to be called on a schedule, not clicked once.
Ad monitoring: launches and pauses, or an honest "not sure"
Most scrapers hand you a snapshot and leave you to diff two multi-thousand-row files yourself. Some can now tell you what launched.
This one also tells you what stopped — and, crucially, refuses to guess when it cannot be certain.
Turn on Track changes (on by default), schedule it daily, and every ad comes back labelled:
change_status | meaning |
|---|---|
baseline | starting point — the first run, or any run that could not scan the full inventory (see below) |
unchanged | still running |
new | launched since your last run — confirmed |
paused | was running, now gone — confirmed |
Set Only output what changed and a scheduled run returns just the launches and pauses — a clean feed for Slack, a webhook, or a dashboard. Runs with nothing to report (the first run, a quiet day, or a partial scan) return no rows and charge only the per-advertiser scan fee.
Change labels only appear when they are true
An ad missing from today's results is only genuinely paused if we looked at the whole inventory. If the run stopped at your result limit, a missing ad might simply be past the limit — and an ad that "appeared" might simply have been past the limit last time. Google does not even return a stable slice: two capped scans of the same big advertiser can overlap on a handful of ads.
Most tools cannot tell those apart, so they report false launches and false
pauses. This Actor tracks whether each run reached the end of the advertiser's
inventory. When both the previous and the current run did, you get new,
paused and unchanged, confirmed. When either scan was partial, it does not
guess: every row is labelled baseline, nothing is reported as new or paused,
and one line in the run log tells you the advertiser's approximate inventory
and exactly what to set Max ads per query to so labels turn on.
A monitor that invents competitor campaign changes is worse than no monitor.
Five things this scraper does that most do not
1. It does not silently lose your video and text ads. In the Transparency Centre's API, image creatives store their content in one field and video and text creatives store it in a completely different one. A scraper that reads only the image field returns HTTP 200, logs success, and quietly drops every video and text ad — roughly 11% of a typical advertiser's inventory. This Actor reads both paths and reports an asset-URL fill rate on every run so you can see it is complete.
2. Domain search finds every ad account, not just one. Brands advertise through several Google Ads accounts — regional entities, resellers, and their media agency. Searching adidas.com returns creatives from adidas International B.V., Adidas America Inc, and their agency MediaCom L.L.C, in one dataset. Resolving a brand to a single advertiser ID structurally cannot see the rest.
3. The output is safe to open. Ad creatives are written by whoever buys the ad, and this Actor's output lands in your spreadsheet, your dashboard and your database. An advertiser that names itself =cmd|'/c calc'!A1 would execute on your machine the moment you open the CSV in Excel. Advertiser names and domains are defused before they reach you, javascript: and data: URLs are never emitted as asset links, and newlines and control characters that corrupt CSV rows are stripped. Legitimate names such as L'Oréal and adidas International B.V. come through untouched.
4. Filters mean what they say. Ask for 20 video ads and you get 20 video ads, even if the Actor has to page through 400 ads to find them — not 2 because it stopped counting early.
5. A quiet run is never a silent failure. The most common complaint filed against scrapers in this niche is some variant of "successful run, zero results" — a green tick, an empty dataset, and no way to tell whether the advertiser has no ads or the scraper broke. This Actor closes that gap: every run logs per-query counts (scanned, pushed, pages), an asset-URL fill rate, and — when a query returns little or nothing — one plain-language line saying why (wrong country is the usual culprit) and what to change. The same numbers land in a RUN_REPORT you can check from the API. You are never left guessing whether zero means zero.
How to use Google Ads Transparency Scraper
- Click Try for free.
- In Advertiser domains or names, enter one or more domains —
nike.com,booking.com. Domains work best. - Choose a Country. Ads are reported per country; an advertiser may run thousands of ads in one and none in another.
- Set Max ads per query.
- Click Start and download the results as JSON, CSV, Excel or HTML.
Input
| Field | Type | Default | Description |
|---|---|---|---|
queries | array | ["nike.com", "brewdog.com"] | Domains or brand names. Domains are preferred. |
region | string | GB | Country code — 110 supported. |
maxResultsPerQuery | integer | 50 | Max ads returned per query. |
formats | array | all | image, video, text. |
activeWithinDays | integer | — | Only ads shown in the last N days. Applied on Google's side — far faster and cheaper. Use 7 for a daily monitor. |
trackChanges | boolean | true | Label each ad new / unchanged / paused vs your last run. |
onlyChanges | boolean | false | Return only launches and pauses. Runs that just record or refresh a baseline (the first run, or any partial scan) return no rows and charge only the scan fee. |
onlyAdsShownSince | string | — | Absolute-date version of activeWithinDays. |
maxRunMinutes | integer | 60 | Wall-clock budget for the whole run. Advertisers there was no time to scan are skipped and not charged. A full-depth scan takes roughly 90 s per advertiser, so raise this for long lists. |
stateStoreName | string | ads-transparency-state | Key-value store holding the change-tracking baselines. Use one store per client to keep tracking histories separate. |
includeCreativeHtml | boolean | false | Include the raw HTML fragment for image ads. |
minFillRate | number | 0.5 | Warn if extraction quality drops below this. |
{"queries": ["nike.com", "adidas.com"],"region": "US","maxResultsPerQuery": 200,"formats": ["image", "video", "text"]}
Output
Each ad creative is one dataset item. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.
{"advertiser_id": "AR18378488041124659201","advertiser_name": "Nike Retail BV","creative_id": "CR07657183496217034753","format": "image","first_shown_iso": "2026-07-08T14:18:12+00:00","last_shown_iso": "2026-08-04T18:30:29+00:00","region": "GB","region_count": 28,"asset_urls": ["https://displayads-formats.googleusercontent.com/ads/preview/content.js?..."],"preview_url": "https://adstransparency.google.com/advertiser/AR18378488041124659201/creative/CR07657183496217034753"}
Every run also writes a RUN_REPORT record to the key-value store with per-query statistics: how many ads were scanned, which advertiser accounts matched, the format breakdown, and the extraction fill rate.
Data fields
| Field | Description |
|---|---|
advertiser_id | Google advertiser account ID (AR…) |
advertiser_name | Advertiser account name |
creative_id | Unique creative ID (CR…) — stable, use it to deduplicate |
format | image, video or text |
asset_urls | Direct URLs to the creative assets |
render_url | Google's renderable preview URL (video and text ads) |
creative_html | Raw, UNSANITISED HTML fragment for image ads (optional, off by default — treat as untrusted and escape it before rendering) |
first_shown / first_shown_iso | When the ad was first observed |
last_shown / last_shown_iso | When the ad was last observed |
region | Country the results were requested for |
region_count | Number of countries this creative runs in |
preview_url | Link to the ad in Google's own Transparency Centre |
destination_domain | The domain the ad points at |
change_status | new, unchanged, paused or baseline |
query | The input query that produced this row |
How much does it cost to scrape Google Ads Transparency Centre?
This Actor talks directly to the Transparency Centre's JSON API. It uses no headless browser, which is what makes it cheap and fast — the default run finishes in about five seconds and 40 ads arrive per request.
Pricing is $0.02 per advertiser scanned + $2.00 per 1,000 ads returned, so cost scales with what you actually ask for:
| What you run | Cost |
|---|---|
| Default run — 2 advertisers, ~55 ads | $0.15 |
| 1 advertiser, 200 ads | $0.42 |
| 1 advertiser, 1,000 ads | $2.02 |
| Daily monitor — 1 competitor, 6 changes | $0.03 |
| Daily monitor — 10 competitors, ~5 changes each | $0.30 |
That last row is the point. With Only output what changed, a scheduled monitor reads a competitor's inventory and bills you only for the ads that actually changed — runs that merely record or refresh a baseline return no rows and charge only the scan fee. Watching ten competitors every day costs about $9 a month.
Apify's free tier is enough to evaluate the Actor properly. There is no rental, no subscription and no monthly fee — you pay per result, and a query that finds nothing costs the $0.02 scan fee and nothing more.
Tips and advanced options
- Use domains, not brand names.
nike.combeatsNike— it catches every ad account promoting that domain, including agencies. - For a daily monitor, use
activeWithinDays(try 7) — notonlyAdsShownSince.activeWithinDayskeeps a stable window, so change tracking compares like with like across runs. A fixed calendar date changes the window every day, which starts a fresh baseline each time: you would be billed for every ad, every day, and never see a change reported. UseonlyAdsShownSincefor one-off historical pulls, not for scheduled monitoring. - Deduplicate on
creative_id. It is stable across runs. - Check
region. Most "no results" reports are an advertiser with no ads in the chosen country. TryUS— it is usually the largest inventory. - Watch the fill rate. The run log prints an asset-URL fill rate. It should be 100%. A sudden drop is an early warning that Google changed its response format.
- Use a date window instead of pulling everything. Setting Only ads active in the last N days asks Google to filter before sending, which is much faster and cheaper. For nike.com the full history is ~10,000 ads while the last 7 days is ~1,000. For monitoring it is also more accurate, because the full history includes ads that stopped running long ago.
- Most runs need no proxy. Very large ones may. Google applies two separate defences: a client-fingerprint check, which this Actor handles for free, and a request-volume limit per IP address. Ordinary runs never come close. Pulling an advertiser's entire 10,000-ad history in one go can trip it — measured, 263 requests in about 70 seconds from a single IP triggers a challenge. If you see a bot-challenge error, either narrow the date window, lower Max ads per query, or enable the proxy option. The Actor paces itself automatically on large scans and stops cleanly with the ads it already collected rather than failing outright.
FAQ, disclaimers and support
Is scraping the Ads Transparency Centre legal? The Centre is a public, no-login database that Google is legally required to publish under the EU Digital Services Act. This Actor collects advertising data — no logins and no paywalled content. Note that advertiser identity fields can name a natural person where the advertiser is a sole trader, so treat the output accordingly under GDPR. Ad creatives themselves remain the copyright of the advertisers who made them. You are responsible for how you use the data, including compliance with Google's Terms of Service, copyright, and applicable law in your jurisdiction.
My run succeeded but returned zero ads — is it broken? Almost certainly not, and unlike most tools this one tells you why in the run log. The usual cause is the country: ads are reported per country, and an advertiser can run thousands of ads in the US and none in the country you picked. Try US, or the advertiser's home market. Two other causes: unverified advertisers may not appear at all, and a brand name matches less than a domain — search nike.com, not Nike. A zero-ad query costs you $0.02 (the advertiser scan) and nothing per ad.
Why do I get fewer ads than the Transparency Centre shows? Google reports an approximate total per country and caps how deep the result set can be paged. Use maxResultsPerQuery to control depth, and narrow by country.
Why is an advertiser missing? Some advertisers are not verified, and unverified advertisers may not appear. Try the domain rather than the brand name.
Does it get political ad spend data? Not yet. Political ads carry extra disclosures (spend and impression ranges) and are on the roadmap.
Something is broken. Open an issue on the Issues tab — bugs get fixed. If you need a custom field, a different country set, or a tailored integration, that can be arranged too.