Google Ads Transparency Center Scraper
Pricing
from $2.00 / 1,000 ad scrapeds
Google Ads Transparency Center Scraper
See every ad an advertiser is running on Google (Search, YouTube, Shopping, Maps, Play) with first/last shown dates, format, preview creative and ad text, by advertiser ID, advertiser name or domain. Pay per ad.
Pricing
from $2.00 / 1,000 ad scrapeds
Rating
0.0
(0)
Developer
Swaraj Samant Singh
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
See every ad a company is running on Google (Search, YouTube, Shopping, Maps, Play) with first/last shown dates, format, preview creative, regions and ad text, as JSON/CSV/Excel. Look up by advertiser ID, advertiser name or website domain. Pay per ad returned.
Data source: adstransparency.google.com, Google's public ad library. No login, no browser, plain HTTP against the same endpoints the site itself uses.
What you get per ad
{"advertiserId": "AR01625195283841286145","advertiserName": "Shopify Inc.","creativeId": "CR13279474632198455297","format": "TEXT","firstShown": "2026-07-06","lastShown": "2026-08-17","daysShown": 44,"previewImageUrl": "https://tpc.googlesyndication.com/archive/simgad/10560228437528131731","adUrl": "https://adstransparency.google.com/advertiser/AR01625195283841286145/creative/CR13279474632198455297?region=anywhere","query": "Shopify -> Shopify Inc.","regions": ["US"],"regionDetails": [{ "region": "US", "lastShown": "2026-08-17" }],"text": ["Shopify","www.shopify.com/","Cheap Wholesale Products for Resale: 2026 Buying Guide","Cheap wholesale products for resale can deliver high margins. Learn where to source, how to vet suppliers, and which items sell best online. 100+ Professional Themes."]}
| Field | Always | Meaning |
|---|---|---|
advertiserId, advertiserName | yes | Google advertiser (AR...) and its verified name |
creativeId | yes | Google creative ID (CR...), unique per ad; rows are deduplicated on it |
format | yes | TEXT, IMAGE or VIDEO (Google's classification) |
firstShown, lastShown | almost always | Dates the ad was first/last served (UTC). Missing only when Google omits them |
daysShown | yes | Google's count of days the ad was served |
previewImageUrl | when Google stores a screenshot | Static preview image of the ad |
adUrl | yes | The ad's page on the Transparency Center |
matchedDomain | domain queries | The domain that matched your query |
advertiserUnverified | when true | Advertiser has not completed Google's verification |
query | yes | Which input entry produced this row |
regions, regionDetails | with includeCreativeDetails | Countries the ad was shown in, with per-country first/last dates where Google provides them |
text, creativeImageUrls | with includeCreativeDetails, when Google renders the ad as HTML | Visible ad copy (headline, description, display URL...) and creative image URLs |
previewScriptUrl | when Google renders the ad as HTML | Google's preview renderer URL for the ad |
payerName | with details, when different from advertiser | The entity that paid for the ad |
raw | with includeRaw | Parsed upstream response, for debugging |
Fields the source does not provide are omitted rather than filled with nulls or guesses. In particular there is no click-through/landing URL and no impression or spend numbers for non-political ads. Google does not expose them.
Input
{"advertiserIds": ["AR16735076323512287233"],"advertiserNames": ["Shopify"],"domains": ["notion.so"],"region": "anywhere","format": "all","platform": "all","dateFrom": "2026-01-01","dateTo": "2026-08-17","maxAdsPerAdvertiser": 100,"includeCreativeDetails": false}
| Field | Default | Notes |
|---|---|---|
advertiserIds | [] | AR... IDs from any adstransparency.google.com/advertiser/AR... URL. Most precise |
advertiserNames | [] | Free text. Google's name search is a prefix match that is not ranked by size, so the actor fetches 50 candidates and picks the verified advertiser with the most ads. The choice is logged ("Shopify" -> Shopify Inc. (AR0162..., CA, ~80000 ads)). Raise maxAdvertisersPerName to take more than one |
domains | [] | Returns ads from every advertiser whose ads link to that domain: the brand itself, resellers, affiliates and anyone linking to a page hosted there (for notion.so that includes unrelated Notion-hosted sites). matchedDomain is set on each row; filter on advertiserName if you only want the brand |
region | anywhere | ISO country code (US, GB, IN, ...). Filters to ads shown in that country |
format | all | text / image / video |
platform | all | search / youtube / shopping / maps / play |
dateFrom, dateTo | none | YYYY-MM-DD. Ads that were served inside the window |
maxAdsPerAdvertiser | 100 | Per advertiser ID (or per domain query). Newest activity first |
includeCreativeDetails | false | Adds regions and, where possible, text. Costs 1-2 more requests per ad, so 100 ads take about 10 minutes at the default pace |
includeRaw | false | Attach parsed upstream data |
minDelayMs | 2500 | Pause between requests. Measured: one IP survives ~50 requests/min for only 1-2 minutes before Google's wall, but 20-25/min for hundreds of requests |
proxyConfiguration | Apify datacenter | Sessions rotate automatically on a 429/captcha response |
At least one of advertiserIds, advertiserNames, domains is required.
Pricing
Pay per event:
| Event | Price |
|---|---|
| Actor start | $0.005 per run |
| Ad scraped | $0.002 per ad row |
1,000 ads = about $2.00 plus a fraction of a cent for the start. Set "Maximum total charge" on the run to cap spend; the actor stops cleanly when it is reached and you keep everything already scraped. Details mode does not cost extra per ad, it only takes longer.
Limitations
- Ad text needs
includeCreativeDetailsand is not available for every ad. Google stores many ads (especially older text ads and most image/video ads) only as a screenshot. Those rows havepreviewImageUrlbut notext. There is no OCR. - No landing URLs, impressions or spend. The Transparency Center does not publish them for regular ads. Political-ad spend data is out of scope.
- Name search is Google's prefix search. "Nike" matches 155 advertisers named Nike-something. The actor's ranking (verified, then ad volume) picks the right one in the cases tested (Nike, Shopify), but for exotic brands pass the domain or the advertiser ID instead. Check the log line that shows which advertiser was chosen.
- Rate limits. Google returns 429 or a captcha redirect once one IP exceeds roughly 50 requests/min for more than a minute; the wall then lasts about an hour for that IP. The actor paces requests (
minDelayMs, default 2.5s = 24/min, measured safe for 200+ requests), uses HTTP/1.1 (Google walled the HTTP/2 client path much sooner in tests), and on a wall backs off (5s, 15s, 45s, 135s) and rotates to a new proxy session. Local runs without a proxy at the default pace are fine for a few hundred requests. - One request fetches 40 ads, so 100 ads per advertiser is 3 requests. Domain queries with many advertisers can be large; use
maxAdsPerAdvertiserand the filters. - The protocol is Google's internal RPC (proto-JSON), documented at the top of
src/atc.js. Field numbers can change without notice; the actor fails loudly (HTTP 400 in the log) rather than returning wrong data if that happens.
FAQ
Which advertiser did "advertiserNames" pick? Read the run log: "Shopify" -> Shopify Inc. (AR01625195283841286145, CA, ~80000 ads, verified). Every row also carries query so you can trace it back.
Why fewer ads than the site shows? maxAdsPerAdvertiser caps each target; region/format/platform/date filters apply at the source; and duplicate creatives (the same ad surfacing for two of your queries) are emitted once.
Can I get the actual image or video file? previewImageUrl is a direct image URL for screenshot previews. For HTML-rendered ads creativeImageUrls lists the images inside the ad (with details on). Video ads expose a thumbnail, not the video.
How fresh is the data? Live from Google at run time. lastShown of an active ad is usually today or yesterday.
Does it use a browser? No. Plain HTTP against adstransparency.google.com/anji/_/rpc/..., which is why it runs on 256 MB.
Local development
npm install# put your input in storage/key_value_stores/default/INPUT.jsonapify run # or: npm startnpm test # offline parser checks + one live check (skips when offline / rate limited)
To exercise pay-per-event locally: ACTOR_TEST_PAY_PER_EVENT=1 ACTOR_MAX_TOTAL_CHARGE_USD=4 npm start charges $1 per event and stops after the start event plus three ads.