Google Ads Transparency Scraper & Ad Monitor avatar

Google Ads Transparency Scraper & Ad Monitor

Pricing

Pay per event

Go to Apify Store
Google Ads Transparency Scraper & Ad Monitor

Google Ads Transparency Scraper & Ad Monitor

Monitor competitor Google ads: export any advertiser's Search, YouTube, Shopping, Maps & Play ads from the Ads Transparency Center with headlines, OCR text for image ads, CTAs, regions and first/last shown dates. Monitor mode outputs only new or changed ads. No login.

Pricing

Pay per event

Rating

0.0

(0)

Developer

SingletonOps

SingletonOps

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Features

Limited permissions

Share

Monitor competitor Google ads from the public Google Ads Transparency Center: every Search, YouTube, Shopping, Maps and Play ad an advertiser runs, with headlines, OCR text for image ads, CTAs, regions and first/last shown dates. Monitor mode outputs only new or changed ads. No login. Built by SingletonOps (a brand of Vibex LLC).

Quickstart: your first run in 2 minutes

  1. Click Try for free (free Apify account, no card needed).
  2. The form is already filled in: nike.com, region US, ads shown in the last 30 days, 20 ads, creative details and OCR on. Keep it, or replace nike.com with your competitor's domain.
  3. Click Start. Our test of this input (without the date filter) returned 20 ads in 11 seconds.
  4. Open the Output tab: headline, description, CTA, format, platforms and first/last shown dates per ad. Download as CSV, Excel or JSON.
  5. To keep watching: Save as task, turn on Only new or changed ads, and add a weekly schedule. Later runs output only new, changed and stopped ads.
{
"advertisers": ["nike.com"],
"region": "US",
"dateFrom": "30 days",
"maxAds": 20
}

A 20-ad first run costs about $0.03 at the proposed price (see Pricing; the Pricing tab on the Store page is authoritative).

Sample output (real run)

Real rows from a small test run on 2026-10-12 (input {"advertisers": ["nike.com"], "region": "US", "maxAds": 20}, 20 ads in 11 s). Text is shortened here; all 20 full records are in samples/first-run-nike-us-20-ads_2026-10-12.json, unedited except that the newer firstSeenDate, lastSeenDate and daysRunning fields were added offline from each row's own firstShown/lastShown. 19 of the 20 ads have been running for 180+ days, so longRunningOnly: true would keep 19.

formatheadlinedescriptionCTAtextSourcefirstShownservedDaysdaysRunningplatforms
TEXTNike® Official SiteNike® offers ultimate selection of gear, accessori…websitenative2023-11-168701062MAPS, SEARCH, SHOPPING, YOUTUBE
TEXTShop The Newest Nike® StylesNike® Kevin Durant basketball shoes for every athl…websitenative2023-11-179011061MAPS, SEARCH, SHOPPING, YOUTUBE
TEXTNike® Golf Pants & MoreHit the links with the latest Nike® golf gear to c…websitenative2023-11-169001062MAPS, SEARCH, SHOPPING
IMAGELeBron James Los Angeles Lakers City Edition …——native2026-06-0391132SEARCH, SHOPPING, YOUTUBE
TEXTKids Crew Socks. Nike.comShop The Official Nike Store For The Latest Nike S…—ocr2022-11-3013621413MAPS, SEARCH, SHOPPING, YOUTUBE
TEXTShop Nike® Socks - Shop Nike® Online - Get Ac…Comfortable, breathable, and performance focused. …—ocr2023-11-168991062MAPS, SEARCH, SHOPPING, YOUTUBE
TEXT—Nike Clothing Is Designed For Performance And Tota…websitenative2022-11-3013591413MAPS, SEARCH, SHOPPING, YOUTUBE

The last row is a Maps/local ad with a dynamic headline: Google stores no headline text for it, so headline is null rather than guessed.

A domain returns every advertiser account whose ads point to it: this run found 3 (Nike, Inc. with 18 ads, Nike Retail BV and Nike Japan with 1 each). Group or filter by advertiserName, or use an AR… ID for one account. On your own domain, that's how you spot resellers and affiliates.

Monitor-mode rows look the same plus changeType and changedFields. Real example: samples/monitor-rerun-zalando-de-first3_2026-10-09.json: the first 3 rows of a real second monitor-mode run on Zalando SE in Germany, with that run's OUTPUT counts. Unchanged ads are checked but not saved, so they cost nothing.

Data comes from the public Google Ads Transparency Center. Search by advertiser name, website domain or advertiser ID and get clean, structured ad data: headlines, descriptions, images, YouTube videos, first and last seen dates, regions, platforms and impression ranges. Turn on monitor mode to get only the ads that are new or changed since the last run.

Use it as a Google ad library / ad spy tool for PPC competitor research: see the exact ad copy, creatives, CTAs and run dates of any competitor, export them to CSV/Excel/JSON, and get alerted when they launch new ads.

No browser, no login, no Google account. The actor calls the same lightweight JSON endpoints the Transparency Center website uses, so runs are fast and cheap.


What does Google Ads Transparency Center Scraper do?

  1. Resolves each input to Google advertiser IDs: names (fuzzy-matched, with the strongest advertiser picked), domains (every advertiser that runs ads for that site), IDs (AR…) or full Transparency Center URLs.
  2. Lists that advertiser's ads with your filters: region (any of 250 countries), date range, format (text, image, video) and platform (Search, YouTube, Shopping, Maps, Play).
  3. For each ad (optional, on by default) it fetches the creative details and the ad preview, and pulls out the headline, description, call to action, display URL, landing domain, image URLs and YouTube video URLs, plus per-region statistics (first and last shown, impression ranges, platforms). Text ads that Google archived only as a screenshot are read with OCR (on by default, see below).
  4. In monitor mode, it compares each ad with a snapshot from the previous run and outputs only new and changed ads (plus stopped ones, see the FAQ), along with the exact fields that changed.
  5. Writes a run summary (OUTPUT) and a data-quality report (QUALITY_REPORT) to the key-value store.

Use cases for PPC teams

  • Monday new-ad check without the clicking. Schedule a weekly run in monitor mode (onlyNewOrChanged) for each competitor domain and read only the new, changed and stopped rows, with changedFields showing what moved.
  • Find the ads worth copying. Turn on longRunningOnly (or set minDaysRunning, e.g. 90) to keep only ads a competitor has kept running for 6+ months, the ones their tests keep picking. Every row has firstSeenDate, lastSeenDate and daysRunning; sort by daysRunning or numServedDays.
  • See when a promotion really ended. lastSeenDate is the last day Google showed the ad, so a sale ad whose lastSeenDate stopped moving has stopped running, whatever the landing page still says.
  • Catch offer and landing-page changes. changed rows flag edits to headline, description, CTA or landingDomain, often the first sign of a new promotion.
  • Spot resellers and affiliates on your brand. Search your own domain to see every advertiser running ads that point to it, including ones you didn't authorize.
  • Agency audits and pitches in minutes. Export a prospect's full competitor ad library (Search, YouTube, Shopping) to Sheets or Excel, by country (region) and date range.
  • Read image-only text ads. Built-in OCR fills headline and description from archived screenshots (textSource: "ocr"), so text ads aren't blank rows.

Also used by creative strategists (swipe files of YouTube, image and Shopping creatives by country), market-entry research (which advertisers are active in a region, on which platforms) and compliance teams (archive what an advertiser showed in a region and period).

Why use this actor?

This actorTypical Transparency scrapers
InputAdvertiser name, domain, ID or URL, plus free-text search terms. Mix many in one runUsually one URL or one query
MonitoringBuilt-in onlyNewOrChanged mode with per-field change detection (changeType, changedFields)Re-scrape everything and diff it yourself
PlatformsEvery ad is tagged with the surfaces it ran on, including outside the EU (platform-membership scan)Platforms often only for EU ads
ReliabilityRetries with exponential backoff and jitter, proxy session rotation, automatic escalation to residential proxy when rate-limited, partial results instead of crashesFails the whole run on rate limits
TransparencyOUTPUT run summary and QUALITY_REPORT with field completeness, speed and estimated cost on every runNo quality metrics
Image-only text adsBuilt-in OCR reads headline, description and display URL from the archived screenshot, marked textSource: "ocr", cached per creativeEmpty fields
CostPure HTTP/JSON plus lightweight WASM OCR, 512 MB default (256 MB works), about 1.5 KB of proxy traffic per adOften headless browsers

What data can I extract?

FieldDescription
advertiserId, advertiserName, advertiserLegalName, advertiserCountry, advertiserVerifiedWho is paying for the ad
creativeId, adDetailUrlStable ad ID and link to the ad on the Transparency Center
formatTEXT, IMAGE or VIDEO
firstShown, lastShown, numServedDaysWhen the ad ran (Google's timestamps) and how many days Google says it was served
firstSeenDate, lastSeenDate, daysRunningAd longevity: first and last shown as UTC dates (YYYY-MM-DD), and daysRunning = days from first to last, counting both days (same day = 1). null when Google gives no date; never guessed
regions, regionStats[]Countries where it ran, with per-country dates, impression ranges and platforms
platformsGOOGLE_SEARCH, YOUTUBE, GOOGLE_SHOPPING, GOOGLE_MAPS, GOOGLE_PLAY
impressionsMin, impressionsMaxImpression range (Google only publishes this for some regions, mainly the EU/EEA)
headline, description, text, callToActionAd copy pulled from the rendered preview, or from the ad image via OCR
textSource, ocrConfidencenative (from the preview), ocr (read from the ad image) or null (no text found); OCR confidence 0–100
imageUrls, videoUrls, previewUrlCreative assets (YouTube links for video ads)
displayUrl, landingUrl, landingDomainWhere the ad points
variantsCountNumber of creative variations Google shows
queryWhich input and filters produced the row
changeType, changedFieldsMonitor mode only: new, changed or stopped, plus which fields changed (running when an ad stopped or started again)
rawOptional raw API payloads (includeRawData)

Setup: how to monitor competitor Google ads

  1. Click Try for free / Start.
  2. Enter one or more advertisers (for example nike.com, Zalando, AR15589870916631265281) or search terms.
  3. Optionally choose a region, date range, format and platform.
  4. Set Max ads per advertiser (prefilled 20 for a quick first run; 100 when omitted via API).
  5. Run it, then download the data as JSON, CSV or Excel, or connect it to Make, Zapier, n8n, Slack or Google Sheets.

For ongoing competitor tracking, save the input as a task, turn on Only new or changed ads, and add a schedule (daily or weekly).

Input examples

All recent ads from a brand's domain

{
"advertisers": ["nike.com"],
"maxAds": 200
}

Video ads on YouTube in Germany in the last 90 days

{
"advertisers": ["Duolingo"],
"region": "DE",
"format": "VIDEO",
"platform": "YOUTUBE",
"dateFrom": "90 days",
"maxAds": 100
}

Discover advertisers by search term (top 2 matches each)

{
"searchTerms": ["adidas", "running shoes"],
"maxAdvertisersPerSearchTerm": 2,
"dateFrom": "30 days",
"maxAds": 50
}

Weekly competitor monitor (only new or changed ads)

{
"advertisers": ["competitor-one.com", "Competitor Two GmbH", "AR15589870916631265281"],
"region": "US",
"onlyNewOrChanged": true,
"stateStoreName": "my-competitor-monitor",
"maxAds": 500
}

Long-running ads only (6+ months): a competitor's proven winners

{
"advertisers": ["nike.com"],
"region": "US",
"longRunningOnly": true,
"maxAds": 200
}

longRunningOnly keeps ads with daysRunning of 180 or more. For another bar, set minDaysRunning instead (for example 90); if both are set, the larger one applies. Ads that don't qualify are skipped before their details are fetched where possible, and are never saved or charged. maxAds still counts every ad checked, so raise it to find more.

Fast, low-cost listing (no ad copy, about 1,000 ads per minute)

{
"advertisers": ["amazon.com"],
"includeCreativeDetails": false,
"maxAds": 1000
}

Dates accept absolute values (2026-01-31) or relative ones (30 days, 2 weeks, today).

Text from image-only ads (OCR)

For many text ads (especially older and EU ones), Google keeps only a screenshot of the ad. With extractTextFromImages on (the default), the actor reads the headline, description and display URL from that screenshot using Tesseract (WASM, no external service, no extra proxy traffic: images are downloaded directly).

  • It runs only for TEXT ads whose preview has no text and that have an archived image, and only when includeCreativeDetails is on. Ads with native text are never OCR'd.
  • The layout is read from the screenshot's colours: the blue line is the headline, the gray block under it is the description, the URL line above the headline is the display URL. Sitelinks, ratings and "App installed" rows are left out.
  • Fields read this way carry textSource: "ocr" and ocrConfidence. The full list of recognised lines goes into text.
  • Results are cached per creative in the google-ads-transparency-cache key-value store, so a monitor rerun (or any later run) never OCRs the same image twice. OCR text isn't used for change detection; a new image shows up as a media change.
  • ocrLanguages picks the models. The default is English, German, French, Spanish, Italian, Dutch, Portuguese and Polish (bundled). You can add others (Nordic, Czech, Greek, Turkish, …); those are downloaded at run start.
  • OCR is CPU-bound. At 512 MB it takes about 5–9 s per image and at 2,048 MB about 1.4 s, at roughly the same cost per image. For large OCR-heavy pulls, raise the memory to go faster. Below 512 MB the actor limits OCR to 3 languages.
  • Turn it off (extractTextFromImages: false) when you only need ad metadata or want maximum speed.

On our test sample of 20 OCR'd ads, 16 of 20 headlines and 15 of 20 descriptions came out exactly right. Most of the remaining errors were one to four wrong accented characters (for example ß, å, ł). One ad had a product photo covering the text. All 20 display URLs were correct.

Output sample (one full JSON record)

{
"advertiserId": "AR18378488041124659201",
"advertiserName": "Nike Retail BV",
"advertiserLegalName": "Nike Retail BV",
"advertiserCountry": "NL",
"advertiserVerified": true,
"creativeId": "CR11779417970759958529",
"format": "TEXT",
"firstShown": "2025-10-24T16:24:40.000Z",
"lastShown": "2026-10-09T13:37:11.000Z",
"numServedDays": 351,
"firstSeenDate": "2025-10-24",
"lastSeenDate": "2026-10-09",
"daysRunning": 351,
"regions": ["AT", "DE", "LU"],
"regionStats": [
{
"regionCode": "AT",
"regionName": "Austria",
"firstShown": "2025-10-25",
"lastShown": "2026-10-06",
"impressionsMin": 0,
"impressionsMax": 1000,
"platforms": [{ "platform": "GOOGLE_SEARCH", "impressionsMin": 0, "impressionsMax": 1000 }]
}
],
"platforms": ["GOOGLE_MAPS", "GOOGLE_SEARCH"],
"impressionsMin": 10000,
"impressionsMax": 15000,
"headline": "Aktuelle Workout-Schuhe",
"description": "Entdecke {Keyword:Nike schuhe} online auf Nike.com – der offiziellen Nike Website.",
"callToAction": null,
"textSource": "native",
"ocrConfidence": null,
"imageUrls": [],
"videoUrls": [],
"displayUrl": "nike.com",
"landingUrl": null,
"landingDomain": "nike.com",
"variantsCount": 1,
"adDetailUrl": "https://adstransparency.google.com/advertiser/AR18378488041124659201/creative/CR11779417970759958529?region=anywhere",
"query": { "input": "nike.com", "type": "domain", "region": "anywhere", "format": "ALL", "platform": "ALL" },
"detailsIncluded": true,
"scrapedAt": "2026-10-09T13:54:51.775Z"
}

The real previewUrl and text fields are included as well; they're left out here to keep the sample short. Rows produced in monitor mode also carry "changeType": "new" | "changed" | "stopped" and "changedFields": ["regions", "headline", …].

Key-value store records

  • OUTPUT: run summary with status (SUCCEEDED, PARTIAL or FAILED), each query's resolution and ad counts, monitor counts (new, changed, unchanged), charging (payPerEvent, chargedEvents, chargeLimitReached), HTTP statistics, errors and estimated cost.
  • QUALITY_REPORT: per-field completeness (overall and by format), ads per minute, proxy traffic, error categories and any feedback you sent with the run.

Alerts: get new competitor ads in Slack, email or a sheet

The actor finds the changes; Apify delivers them. A typical PPC alert setup:

  1. Save your input as a task with onlyNewOrChanged: true and a fixed stateStoreName (for example competitors-us). Use one state store per monitor so tasks don't overwrite each other's snapshots.
  2. Add a schedule to the task (weekly on Monday morning, or daily for fast-moving competitors).
  3. On the task's Integrations tab, connect Slack, email, Google Sheets, Zapier, Make or n8n, or add an Apify webhook on Run succeeded that points at your endpoint. Each run's dataset contains only new, changed and stopped ads, so the alert is the change list, not the whole library.
  4. Optional: set reportIssueWebhook to get a POST when a run has errors, ends PARTIAL, or carries feedback, so a broken monitor never fails silently.

The first monitor run outputs the full baseline (every current ad as new) unless you turn off emitBaselineOnFirstRun. With it off, the first run only saves the snapshot and outputs (and charges) nothing. Monitor state is stored per query, so several tasks can share one store or stay separate.

How much does it cost?

The actor is pure HTTP plus an optional OCR step and runs at 512 MB by default. On our platform test runs, compute plus residential-proxy usage came to roughly $0.04–0.07 per 1,000 ads with full details and OCR off, and about $0.007 per 1,000 ads in list-only mode (includeCreativeDetails: false). OCR adds about $0.18–0.30 per 1,000 ads that actually need OCR, so the total depends on the advertiser. On nike.com (25% of ads needed OCR) it was $0.13 per 1,000 ads, and on Zalando DE (97% image-only) it was $0.23 per 1,000. These are platform usage figures from our tests, not the price.

Pricing

Pay-per-event, one event that matters:

EventPriceWhen it's charged
ad$0.0017 per ad ($1.70 per 1,000 ads)One ad creative saved to the dataset
apify-actor-start$0.00005 per runApify's standard run-start event (covers the first seconds of compute)

The Pricing tab on the Store page is always the authoritative price.

  • You pay only for ads saved to the dataset. The OUTPUT summary and QUALITY_REPORT records are free.
  • In monitor mode (onlyNewOrChanged) only new or changed ads are saved, so unchanged ads cost nothing. Example: a weekly monitor of 5 competitors that finds 40 new or changed ads costs about $0.07 per run.
  • A one-off audit pull of 1,000 ads costs about $1.70.
  • Set Max cost per run in the run options to cap your spend. When the cap is reached, the actor stops cleanly, keeps what it has saved, and marks charging.chargeLimitReached: true in OUTPUT. In monitor mode, ads it didn't get to are still reported on the next run.

Proxy

By default the actor uses Apify Residential proxy. Only small JSON responses go through it, so traffic is about 1.5 KB per ad, and ad previews are fetched directly. Google rate-limits datacenter IPs aggressively. If you choose datacenter or no proxy and the actor hits repeated rate limits, it switches to residential automatically (proxyFallbackToResidential, default on).

FAQ

Is this a Google ad spy tool / ad library like the Meta Ad Library? Yes, for Google. It exports the same public data as the Google Ads Transparency Center, in bulk and in a structured format, so you can research competitors' ads across Search, YouTube, Shopping, Maps and Play.

Does it show ad spend, keywords or CTR? No. Google doesn't publish spend, targeted keywords or performance. You get the creatives, copy, dates, regions, platforms and (where Google publishes them) impression ranges.

What does textSource mean? native means the text came from Google's rendered ad preview, ocr means it was read from the archived ad image (with ocrConfidence), and null means no text was available.

Can I export to CSV or Google Sheets? Yes. Every Apify dataset downloads as JSON, CSV, Excel or XML, and integrations push it to Google Sheets, Slack, Make, Zapier or n8n.

Can I search by keyword, like "running shoes"? The Transparency Center only searches advertiser names and domains, not ad text. searchTerms returns the best-matching advertisers (and domains). For brand terms this works well. A generic phrase may match a small advertiser whose name contains those words.

Why are some text-ad headlines empty? For many older or EU text ads, Google only stores an image snapshot of the ad. With OCR on (default), the actor reads the text from that image (textSource: "ocr"). Headlines stay null when the ad has no image to read, or when the headline is dynamic (keyword insertion or local ads) and Google stores only a placeholder. The actor doesn't make up a headline in those cases.

Why are impressions missing? Google publishes impression ranges only for some regions (mostly the EU/EEA) and for political ads.

Is there a "Display" platform filter? No. The Transparency Center's platform filter only offers Search, YouTube, Shopping, Maps and Play, so the actor offers the same five.

Does it detect removed ads? Yes, in monitor mode. An ad is saved once as changeType: "stopped" when its lastShown date is at least stoppedAfterDays days old (default 3) and didn't advance since the previous run, or when it is missing from a complete listing two runs in a row (listings cut short by maxAds, an error or a cost limit never count). A stopped ad that runs again comes back as changed with changedFields: ["running"]. Turn this off with reportStoppedAds: false.

How is daysRunning counted? It's lastSeenDate minus firstSeenDate plus 1, so both the first and the last day count (an ad shown on one day only has daysRunning: 1). The dates are the UTC calendar dates of Google's firstShown and lastShown. It's the calendar span, not numServedDays (the days Google says the ad was actually served): an ad that paused for a while has a lower numServedDays. Google counts days in its own time zone, so the two can also differ by a day. If either date is missing, daysRunning is null; with minDaysRunning or longRunningOnly on, those ads are left out. Our Meta Ad Library monitor uses the same three fields and the same definition.

Does the long-running filter work in monitor mode? Yes. Only ads that pass the filter start being tracked, so an ad shows up as new the run it first reaches the bar. Ads already tracked stay in, so their changes and their stop are still reported. Turning the filter on starts its own baseline (it doesn't reuse the snapshot of the same query without the filter). stopped rows for tracked ads are always reported; they carry lastSeenDate but firstSeenDate/daysRunning are null because the snapshot doesn't keep the first shown date.

What happens if an advertiser doesn't exist? That query is reported as NOT_FOUND in OUTPUT, and the other queries still run. If every query fails, the run fails with a clear message.

How do I report a problem? Use the Issues tab, or put a note in the feedback input field. It's saved to QUALITY_REPORT and reviewed weekly. You can also set reportIssueWebhook to get a POST whenever a run has errors.

Limits

  • Only public Transparency Center data: no spend, keywords, audiences or click data.
  • Google may rate-limit heavy usage; the actor retries and falls back to residential proxy, but very large pulls can end as PARTIAL.
  • The actor paginates (40 ads per page) until maxAds is reached or there are no more pages. maxAds applies to each advertiser input, domain, or resolved search-term advertiser. With minDaysRunning / longRunningOnly, maxAds counts ads checked, not ads saved.
  • OCR text can contain small character errors, mostly accented letters in languages outside ocrLanguages, and text covered by a product image. Check ocrConfidence and textSource.
  • landingUrl is rarely exposed by Google. landingDomain comes from the display URL or the preview.
  • Date filters cover what the Transparency Center exposes (the actor searches from 2018-01-01 onward when no start date is set).
  • With details on and OCR off, our tests ran at about 100–170 ads per minute. OCR is CPU-bound: at 512 MB, expect roughly 10–25 ads per minute when most ads are image-only, or about 35 per minute at 2,048 MB. For very large pulls, use list-only mode first.

This actor only collects data that Google publishes in the public Ads Transparency Center, without logging in. It doesn't collect personal data about individuals. Still, the results can include advertiser names and other information. Make sure your use complies with Google's Terms of Service and the laws that apply to you (for example GDPR). If you're unsure, consult your lawyer. You can read more in Apify's blog post on the legality of web scraping.

Support

Found a bug or need a field? Open an issue on the Issues tab. We review issues, feedback and quality reports every week.

Built and maintained by SingletonOps, a brand of Vibex LLC. Also from SingletonOps: Meta Ad Library Monitor (new competitor Facebook and Instagram ads), RSS Change Monitor and Sitemap Change Monitor.