Google Ads Scraper - Ad Creatives, Images & Audience Targeting
Pricing
$1.20 / 1,000 creative delivereds
Google Ads Scraper - Ad Creatives, Images & Audience Targeting
Scrape every ad an advertiser runs from Google's Ads Transparency Center: one row per creative with its archived image, format, serving dates, countries, ad wording where Google keeps it readable, and EU audience targeting. Creatives Google holds no content for are never returned.
Pricing
$1.20 / 1,000 creative delivereds
Rating
0.0
(0)
Developer
My Smart Digital
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Google Ads Scraper — every ad an advertiser runs, from the Ads Transparency Center
Reads the public Google Ads Transparency Center and returns one row per ad creative an advertiser has run, with the content Google actually holds for it: the archived image, the ad wording where Google keeps it readable, the serving period, the countries it ran in, and the audience targeting the advertiser had to disclose in Europe.
The one rule this actor follows
It never returns a row it cannot fill, and never writes a value it does not have.
Google's registry hands back a share of creatives it holds no image and no preview for. Returning them produces a dataset of identifiers and dates that cannot be used for anything — and you pay for them all the same. Here they are counted in the run summary and dropped.
Three measurements behind that sentence, all reproducible on your own runs:
| Measured | |
|---|---|
| Creatives returned with no image and no preview | 0 out of 140 delivered, across two advertisers |
adText filled with a placeholder, a template or a fragment of markup | 0 — the field is either real ad wording or null |
audienceTargeting returned as an empty object where Google published nothing | 0 — it is null, which does not mean "targeted nobody" |
Same rule everywhere else: a column the registry never fills is not shipped at all rather than
shipped empty. The exact placement (STATIC_GOOGLE_SEARCH, DYNAMIC_MAPS_PROMOTED_PIN and 68
others) is declared by the registry but never filled on the public endpoint — checked on 60 search
results and 4 detail lookups — so this actor does not offer a placement column.
What you get
One dataset item per creative:
| Field | What it is |
|---|---|
advertiserId, advertiserName | The advertiser as the registry names it |
creativeId | Google's identifier for this creative |
domain | The domain the ad points to |
format | TEXT, IMAGE or VIDEO |
imageUrl, imageWidth, imageHeight | Direct URL of the archived image, when the creative has one — a downloadable visual, not a page to render |
previewScriptUrl | How to render the creative, when it is served as a rendered preview instead of a still image |
adText | The wording of the ad, when Google keeps it as text rather than as a picture. null otherwise, never a placeholder |
displayUrl | The URL shown in the ad, when the creative renders one |
advertiserDisplayName | The name shown in the ad, often more specific than advertiserName |
adTextParts | Every string the creative renders, in order, so nothing is lost by the mapping above |
firstShown, lastShown, daysServed | Serving period, as YYYY-MM-DD |
politicalRegions | Regions where the ad is registered as political, when applicable |
advertiserUnverified, reportedByUser | Flags the registry sets on the creative |
creativeUrl | Link back to the creative's page in the registry |
Sample output
A real row, shortened (a text ad Booking.com ran across 11 countries):
{"advertiserId": "AR02934798844673654785","advertiserName": "Booking.com","creativeId": "CR04485766038394241025","domain": "booking.com","format": "TEXT","imageUrl": null,"previewScriptUrl": "https://displayads-formats.googleusercontent.com/ads/preview/content.js?...","adText": "Išsirinkite ir užsisakykite – geriausi kaimo turizmo sodybų pasiūlymai Lietuvoje...","displayUrl": "www.booking.com/","advertiserDisplayName": "Booking.com","firstShown": "2026-08-19","lastShown": "2026-09-06","daysServed": 18,"advertiserUnverified": false,"creativeUrl": "https://adstransparency.google.com/advertiser/AR02934798844673654785/creative/CR04485766038394241025","legalName": "Booking.com B.V.","countriesServed": 11,"countries": ["IT", "ES", "HR", "LT", "PL", "CZ", "IE", "NO", "DE", "GR", "LV"],"countryDetails": [{ "country": "BE", "geoCriteriaId": 2056, "firstServed": "2023-10-03", "lastServed": "2026-09-05","impressionsLowerBound": 5000, "impressionsUpperBound": 6000, "dataAvailableFrom": null,"bySurface": [{ "surface": "SEARCH", "impressionsLowerBound": 5000, "impressionsUpperBound": 6000 },{ "surface": "YOUTUBE", "impressionsLowerBound": null, "impressionsUpperBound": 1000 }] }],"eeaImpressions": {"impressionsLowerBound": 1250000, "impressionsUpperBound": 1500000,"firstServed": "2023-10-02", "lastServed": "2026-09-05", "dataAvailableFrom": null,"bySurface": [{ "surface": "SEARCH", "impressionsLowerBound": 1250000, "impressionsUpperBound": 1500000 },{ "surface": "YOUTUBE", "impressionsLowerBound": 25000, "impressionsUpperBound": 30000 }]}}
With per-country details switched on
includeDetails adds one lookup per creative and fills six more fields:
| Field | What it is |
|---|---|
legalName | The legal entity behind the advertiser — Booking.com B.V. where the search only says Booking.com |
countriesServed, countries | Number of countries and their two-letter codes |
countryDetails | Per country: Google's geo criteria ID, first and last served dates, the impression bracket where Google publishes one, and its split across Google properties. Sparse by nature — measured on 152 country rows, a first-served date on 59 and an impression bracket on 30 |
eeaImpressions | How many times the ad was shown across the EEA, as a bracket, split by Google property. See below |
variantCount, variantUrls | Every rendering of the creative, where the search returns only one (3 to 4 on the videos tested) |
audienceTargeting, audienceTargetingSignals | See below |
Audience targeting, and what it really is
Google publishes this because the EU Digital Services Act requires it, which is what decides its
coverage: creatives served in the European Economic Area carry it, the others do not. Measured
on 32 creatives — 8 of 8 for a French advertiser, 7 of 12 for booking.com, 2 of 12 for
salesforce.com. Where Google publishes nothing, the field is null.
Five signals, each with what the advertiser included and what it excluded: demographics,
geography, contextual, topicOfInterest, advertiserList.
"audienceTargeting": {"demographics": { "included": true, "excluded": false },"geography": { "included": true, "excluded": false },"contextual": { "included": true, "excluded": true },"advertiserList": { "included": true, "excluded": false }},"audienceTargetingSignals": ["demographics", "geography", "contextual", "advertiserList"]
The registry also declares age, gender and geographic conditions next to these signals. They are never filled on the public endpoint, so nothing is shipped for them.
How many times the ad was shown
eeaImpressions is the volume the ad reached across the European Economic Area, plus its split
between the Google properties it ran on: SEARCH, YOUTUBE, MAPS, PLAY, SHOPPING. Same
disclosure duty as the targeting above, so it lands on exactly the same creatives — measured on 20
creatives across two advertisers, the two agree on all 20.
Google publishes brackets, never counts, and reading them takes two rules:
- The two bounds are independent. is Google saying fewer than a thousand. It is a value, not a gap.{ "impressionsLowerBound": null, "impressionsUpperBound": 1000 }
- A recent ad has no bracket yet, and says when it will.
dataAvailableFromcarries the future date Google will publish the figures on. Rather than an empty cell with no explanation, you get the date to come back on. Measured: 13 of the 16 disclosed creatives had their bracket, the other 3 a publication date.
The same six keys appear inside every countryDetails row, so the same volume is readable country
by country as well as EEA-wide.
Input
| Field | Default | Notes |
|---|---|---|
searchTerm | — | Required. A domain such as booking.com, or an advertiser name |
searchBy | domain | Look up by the domain the ads point to, or by advertiser name |
maxResults | 40 | Up to 1000. Results are paginated 40 at a time |
adFormat | any | text, image or video. Filtering happens at the source, so formats you did not ask for are never fetched or charged |
regions | [] | Google geo target IDs (2250 France, 2840 United States, 2826 United Kingdom) |
servedFrom, servedTo | — | Bounds on the serving period, YYYY-MM-DD |
includeDetails | false | Adds the per-creative lookup described above |
{"searchTerm": "booking.com","maxResults": 40,"adFormat": "video","includeDetails": true}
A RUN_SUMMARY record is written to the run's key-value store: creatives delivered, how many
carried readable ad text, how many were skipped for having no content, pages fetched, and how many
times Google rate-limited the run.
Limits, stated up front
- Ad text is available on a minority of creatives, and the field is empty on the rest. Google archives most ads as a picture of themselves, with the wording baked into the pixels; only the creatives it keeps as a rendered preview carry readable text. Measured across two advertisers, that is around 15% of creatives — but every creative that carries a preview returns its text, and asking for the per-creative details does not raise the share: on 40 creatives archived as images, none gained readable text from the extra lookup. Reading the rest would require OCR, which this actor does not do.
- Audience targeting and impression volumes depend on where the ad ran, for the reason given above. They are a European disclosure, not fields Google fills at random.
- No exact placement, for the reason given above.
- No US impression volumes. The registry declares the field next to the European one, and it came back empty on every creative tested. Nothing is shipped for it.
- Rate limit. The registry caps requests per IP: roughly 40 calls in a row, then every endpoint returns "too many requests" for a few minutes. Requests are spaced out and retried with a growing delay rather than failing the run, so large runs are slower rather than broken.
- Per-country details are capped at 200 creatives per run, because each one costs an extra request against that same rate limit.
- No proxy and no login: the registry answers a plain server IP.
Creatives Google holds no content for are neither returned nor charged.