Google publishes every ad an advertiser runs in its Ads Transparency Center: the creative, the format, when it was first and last shown, and the countries it ran in. Anyone can open it without logging in, which makes it the most direct way to see what a competitor is running on Search, YouTube, Shopping, Maps and Play. It is built for browsing one advertiser at a time, though, not for a table of every creative a brand has live or a morning list of what is new.
This post pulls those ads into Python, builds a competitor sheet, and sets up a daily "new ads only" watch.
Disclosure: I'm Aurelix, and I built the Competitor Google Ads Scraper | Google Ads Transparency API. It's a paid tool (prices below).
What each row holds
One row per ad creative:
-
advertiser_name,advertiser_id,creative_id,ad_idandformat(text,imageorvideo). -
first_shownandlast_shown(ISO 8601 UTC) anddays_shown. -
image_urlandimage_urls(every image variant),preview_url(Google's own preview), and for video adsvideo_urlandyoutube_video_id. -
regions: every country the ad ran in, andregion_detailswith per-country dates, plus impression ranges and platforms where Google publishes them (mainly for the EU). -
platforms(google_search,youtube,google_shopping,google_maps,google_play) where published, andad_url, the ad's page in the Transparency Center.
What you can search for, in one list called targets:
- a brand name such as
"Nike": the advertiser with the most ads whose name starts with it is used (here "Nike, Inc."), and the run status says which one; - an advertiser ID such as
"AR16735076323512287233", or a Transparency Center link copied from the browser; - a website such as
"canva.com": every advertiser whose ads point to that domain.
A competitor's Google ads as a sheet
pip install apify-client import csv import os from apify_client import ApifyClient client = ApifyClient(os.environ["APIFY_TOKEN"]) run = client.actor("aurelix/google-ads-transparency").call( run_input={ "targets": ["canva.com", "Nike"], "region": "US", "maxResultsPerTarget": 200, } ) ads = list(client.dataset(run["defaultDatasetId"]).iterate_items()) fields = ["advertiser_name", "format", "first_shown", "last_shown", "days_shown", "regions", "image_url", "video_url", "ad_url"] with open("google_ads.csv", "w", newline="", encoding="utf-8") as f: w = csv.DictWriter(f, fieldnames=fields, extrasaction="ignore") w.writeheader() for ad in ads: w.writerow({**ad, "regions": ", ".join(ad["regions"])}) print(run["statusMessage"]) The file is a swipe file: every creative with its format, how long it has been running and where. Text ads come back as Google's image of the ad (image_url), because that is how the Transparency Center keeps them; video ads carry their YouTube link.
Which creatives have run the longest
from collections import Counter longest = sorted(ads, key=lambda a: a["days_shown"] or 0, reverse=True)[:10] for ad in longest: print(f"{ad['days_shown']:>5} days {ad['format']:5} {(ad['advertiser_name'] or '')[:30]:30} {ad['ad_url']}") print(Counter(ad["format"] for ad in ads)) print(Counter(country for ad in ads for country in ad["regions"]).most_common(10)) An ad that has run for hundreds of days is one the advertiser keeps paying for, which is usually the best signal of a creative that works. The two counters show the format mix and the countries a competitor spends in.
New ads every morning
run_input = { "targets": ["Wealthsimple", "Neo Financial", "Tangerine Bank"], "region": "CA", "maxResultsPerTarget": 100, "incremental": True, "stateKey": "competitor-google-ads", "slackWebhookUrl": "https://hooks.slack.com/services/...", } With incremental on, the first run returns up to maxResultsPerTarget ads per advertiser. Each later run with the same stateKey returns only creatives Google first showed since the previous check that no earlier run returned; older ads the first run did not reach are skipped, not dripped out as "new". Google lists an advertiser's ads by when they were last shown, so the tool reads each advertiser down to the ads last shown a day before its previous check and stops there: nothing below that line can be new. Save the input as a task in the Apify Console, schedule it daily, and the Slack URL gets the count and the top 10 new ads; nothing is sent when a run finds nothing. webhookUrl posts the same digest as JSON to Zapier, Make or n8n.
Filters
-
region: a two-letter country code (US,CA,GB,DE...) oranywhere. -
startDateandendDate(YYYY-MM-DD): Google applies the range itself and keeps an ad shown at any time in it. -
format:text,imageorvideo.platform:google_search,youtube,google_shopping,google_mapsorgoogle_play. -
maxResultsPerTarget: an exact cap per advertiser or domain;0reads everything. -
includeDetails(on by default): the per-ad detail record with every country, platforms, image variants and the YouTube link. Turn it off for faster, larger lists.
Use cases
- Competitor research: which products and offers a competitor pushes on Google, in which countries, and for how long.
- Creative swipe files: the image and video creatives of a category, refreshed weekly.
- Agency pitches: a prospect's live Google ads and how long each has run, before the first call.
- Lead lists: check a list of company websites and keep the ones that advertise on Google in your market.
Why this tool
- Search by brand name, advertiser ID, Transparency Center link or just a website domain, several in one run.
- The detail record (every country, platforms, image variants, YouTube links) is included in the per-ad price.
- Exact limits: ask for 100 ads per advertiser, get and pay for at most 100.
- An only-new mode for a daily monitor, with a Slack or webhook digest.
- What it doesn't cover: the text of text ads as text. Google keeps most of them only as an image of the ad, and this tool doesn't read text out of images.
Limits worth knowing
- With details on, each ad needs its own request: measured at about 1 second per ad on Apify, roughly 10 minutes per 1,000 ads.
- About 1 in 10 video ads has no YouTube link in Google's preview.
- Google publishes impression ranges and platform splits mainly for ads shown in the EU; elsewhere an ad usually lists only its countries.
- Election ads and party and campaign advertisers are skipped.
The tool reads only what a logged-out visitor sees in Google's public Ads Transparency Center, at a polite pace. It never logs in and never solves CAPTCHAs; if Google keeps refusing, the run ends early with the ads already read and says so. Advertiser names are returned as the Center shows them.
FAQ
Do I need a Google account? No. The tool never logs in.
How do I get one exact advertiser? Open the advertiser in the Transparency Center, copy the page address (it contains an ID starting with AR) and paste it into targets.
Are duplicates charged? No. Each ad is returned once per run even when several targets find it, and with incremental on, ads from earlier runs are skipped and not charged.
Can an AI agent use it? Yes, through Apify's MCP server (https://mcp.apify.com/?tools=aurelix/google-ads-transparency) or the API.
Cost
$1.00 per 1,000 ads on Apify's free plan ($0.90 on Bronze, $0.80 on Silver and higher), detail record and residential proxy included, plus a $0.008 start fee per run. A results page or name lookup that has no ad to return (a website with no ads, a filter that matches nothing, a monitor day with nothing new) costs $0.0004, so a check that finds nothing costs almost nothing. The current prices are on the Store page; Apify's free plan includes $5 of credit a month, enough for about 4,900 ads.

