Google Ads Transparency Scraper
Pricing
from $2.00 / 1,000 scraped ads
Google Ads Transparency Scraper
Extract ad creatives from the Google Ads Transparency Center and see what changed since your last run. Other scrapers list an advertiser's ads; this one flags which are new, which stopped, and which have run longest. Schedule it and the change log builds itself.
Pricing
from $2.00 / 1,000 scraped ads
Rating
0.0
(0)
Developer
Ege
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
Extract ad creatives from the Google Ads Transparency Center — and see what changed since your last run.
Other scrapers answer "what ads is this advertiser running?". This one also answers "what did they change?": which creatives are new, which stopped, and which have been running longest. Schedule it and the change log builds itself.
Output
| Field | Description |
|---|---|
advertiserId | Google advertiser ID (AR...) |
advertiserName | Advertiser display name |
creativeId | Creative ID (CR...) |
format | text, image, or video |
formatCode | Raw format code from the API |
previewUrl | Google-hosted creative preview |
transparencyUrl | Link back to the ad in the Transparency Center |
firstShown | Date the ad first ran |
lastShown | Date the ad last ran |
daysActive | Days between first and last shown |
isActive | Whether lastShown falls inside your active window |
changeType | new, stopped, continuing, or baseline |
previousLastShown | lastShown recorded on the previous run |
Every record carries a transparencyUrl, so you can verify any row against the
real page in one click.
Input
Find an advertiser at adstransparency.google.com and paste either its URL or its advertiser ID:
{"queries": ["AR17828074650563772417"],"mode": "changes","activeWithinDays": 7,"stateKey": "default"}
| Option | Default | Meaning |
|---|---|---|
queries | — | Advertiser IDs or Transparency Center advertiser URLs |
mode | changes | snapshot for a plain extract, changes to track movement |
activeWithinDays | 7 | An ad last shown before this counts as stopped |
maxAdsPerAdvertiser | 500 | Cap per advertiser |
stateKey | default | Namespace for change detection — one per tracked portfolio |
regions | ["anywhere"] | Only anywhere is supported today |
How change detection works
Each run stores a fingerprint of every creative it saw. The next run compares against it:
- new — not present last time
- stopped — gone from the results, or last shown before your active window
- continuing — still running
The first run on a new stateKey has nothing to compare against, so every ad
comes back as baseline and the run summary sets baselineRun: true. It does
not pretend your whole back catalogue just launched.
Use a separate stateKey per portfolio you track. Histories are isolated.
Current limitations
Stated plainly so nothing surprises you:
- Domain and brand-name lookup is not supported. Pass an advertiser ID or
URL. Anything else is listed in
advertisersUnresolvedand is never charged. - Region filtering is not supported. All results are worldwide.
Run summary
Written to the run's own key-value store as RUN_SUMMARY, so each run keeps its
own copy:
{"advertisersRequested": 20,"advertisersResolved": 20,"advertisersUnresolved": [],"advertisersSucceeded": 20,"advertisersFailed": {},"advertisersWithNoAds": ["AR047...", "AR075..."],"successRate": 1.0,"itemsPushed": 360,"changesDetected": 0,"baselineRun": false,"truncatedAdvertisers": ["AR183..."]}
A failure on one advertiser never discards the others' results.
advertisersWithNoAds matters more than it looks: an advertiser can be scraped
successfully and simply have no ads running. That is a different outcome from a
failure, and you should not have to guess which one you got. truncatedAdvertisers
names advertisers that hit your maxAdsPerAdvertiser cap and have more available.
Pricing
$0.002 per ad, $0.004 per detected change. You are charged only for items actually delivered to your dataset.
Development
pip install -r requirements-dev.txtpytest # 57 tests, no network callspytest -m live # contract tests against the real endpointapify validate-schema # run before every push; the build rejects on one bad key
Publishing gotchas are recorded in docs/publishing-notes.md.
normalize.py and differ.py are pure and import neither httpx nor apify,
so the logic that produces the change data is tested entirely from fixtures.