Google Ads Transparency Center Scraper avatar

Google Ads Transparency Center Scraper

Pricing

from $2.00 / 1,000 ad scrapeds

Go to Apify Store
Google Ads Transparency Center Scraper

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

Swaraj Samant Singh

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

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."
]
}
FieldAlwaysMeaning
advertiserId, advertiserNameyesGoogle advertiser (AR...) and its verified name
creativeIdyesGoogle creative ID (CR...), unique per ad; rows are deduplicated on it
formatyesTEXT, IMAGE or VIDEO (Google's classification)
firstShown, lastShownalmost alwaysDates the ad was first/last served (UTC). Missing only when Google omits them
daysShownyesGoogle's count of days the ad was served
previewImageUrlwhen Google stores a screenshotStatic preview image of the ad
adUrlyesThe ad's page on the Transparency Center
matchedDomaindomain queriesThe domain that matched your query
advertiserUnverifiedwhen trueAdvertiser has not completed Google's verification
queryyesWhich input entry produced this row
regions, regionDetailswith includeCreativeDetailsCountries the ad was shown in, with per-country first/last dates where Google provides them
text, creativeImageUrlswith includeCreativeDetails, when Google renders the ad as HTMLVisible ad copy (headline, description, display URL...) and creative image URLs
previewScriptUrlwhen Google renders the ad as HTMLGoogle's preview renderer URL for the ad
payerNamewith details, when different from advertiserThe entity that paid for the ad
rawwith includeRawParsed 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
}
FieldDefaultNotes
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
regionanywhereISO country code (US, GB, IN, ...). Filters to ads shown in that country
formatalltext / image / video
platformallsearch / youtube / shopping / maps / play
dateFrom, dateTononeYYYY-MM-DD. Ads that were served inside the window
maxAdsPerAdvertiser100Per advertiser ID (or per domain query). Newest activity first
includeCreativeDetailsfalseAdds regions and, where possible, text. Costs 1-2 more requests per ad, so 100 ads take about 10 minutes at the default pace
includeRawfalseAttach parsed upstream data
minDelayMs2500Pause 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
proxyConfigurationApify datacenterSessions rotate automatically on a 429/captcha response

At least one of advertiserIds, advertiserNames, domains is required.

Pricing

Pay per event:

EventPrice
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 includeCreativeDetails and 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 have previewImageUrl but no text. 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 maxAdsPerAdvertiser and 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.json
apify run # or: npm start
npm 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.