Google Ads Transparency Center Scraper - Competitor Ads Checker
Pricing
from $0.90 / 1,000 ad (creative row)s
Google Ads Transparency Center Scraper - Competitor Ads Checker
Google Ads checker: does a company run Google Ads? Check a list of domains from $0.002 each: one row per domain (has ads or not, Google's ad count range, the advertisers behind it). Also a Google Ads scraper for competitor ads in the Google ad library: ad creatives with format, preview and dates.
Pricing
from $0.90 / 1,000 ad (creative row)s
Rating
0.0
(0)
Developer
Orbots
Maintained by CommunityActor stats
0
Bookmarked
9
Total users
9
Monthly active users
a day ago
Last modified
Categories
Share
Google Ads Transparency Center Scraper - Competitor Ads
Unofficial tool. Orbots is not affiliated with, sponsored by, or endorsed by Google. "Google", "Google Ads" and "Ads Transparency Center" are trademarks of Google LLC, used here only to describe the public data this Actor collects.
Two questions, one Actor, straight from the public Ads Transparency Center. Does this company run Google Ads? Give it a list of domains and get one row per domain: yes or no, Google's own estimate of how many ads, the verified advertisers behind the domain and, if you want, a profile of how active the advertiser is. What ads is this advertiser running? Give it a brand name, a domain or an advertiser ID and get one clean row per ad on Search, YouTube, Display, Shopping and Maps: format, preview asset, first and last shown date, days active, and (optionally) the countries each ad ran in. No login, no browser, no cookies. You only pay for rows that are actually delivered.
Does this company run Google Ads? Check a list of domains
Set outputMode to advertisers and list the domains (brand names and advertiser IDs work too). One row comes back per entry:
{"queries": ["shopify.com", "hubspot.com", "notion.so", "canva.com", "figma.com"],"regions": ["US"],"outputMode": "advertisers","profile": false}
Each row answers three questions:
- Does it advertise on Google at all?
has_ads, true when the Center lists at least one ad shown in yourregions. Emptyregionsmeans anywhere, so a domain can befalsefor["US"]andtruefor[]. - How big is it?
total_ads_minandtotal_ads_max, Google's own estimated range, not our count. - Who is behind it?
advertisers_found, every verified advertiser seen on the page the check reads. A domain can be used by several: the brand, its retail arms, its media agencies.
Rows also carry query, advertiser_id, advertiser_name, domain, regions, transparency_url and scraped_at. A domain with no ads still gets its row, with has_ads: false: a no is an answer, delivered and charged like a yes. A brand name that matches no advertiser, or a query the Center refuses, yields no row and no charge, and the run status names it, so a refusal never looks like a no.
Price: $0.002 per check row plus $0.005 once per run. One domain in its own run costs $0.007; 1,000 domains in one run cost $2.005. A run that delivers nothing costs nothing.
Add "profile": true and the same row also says how active the advertiser is, computed from the same page the check already reads (no extra request) and based on up to 100 of the most recent ads the Center lists for your query and regions: ads by format (format_image_count, format_text_count, format_video_count), oldest_ad_first_shown, newest_ad_first_shown, latest_ad_last_shown, active_last_30_days with ads_active_last_30_days, longest_running_days, up to three sample_ads with preview links, plus ads_sampled and profile_basis saying what the numbers are based on. The profile is its own event, $0.01 per profiled row, charged only when the check found ads. Countries are not part of the profile: per-country dates come with includeDetails in creatives mode.
Rows are plain JSON with stable field names, ready for n8n, Make, Zapier, Clay or a spreadsheet: one domain per run enriches records one at a time; one run for a whole list pays the start fee once. The dataset downloads as JSON or CSV, and the "Advertiser checks" view in the dataset tab shows the check columns side by side.
Run it after another Actor (integration mode)
This Actor can take its queries from the dataset of another Actor's run. Open the Actor that produces your list (a Google Maps scraper that writes a website per place, a company directory scraper, one of your own) and go to its Integrations tab. There are two ways to connect this Actor there:
- Add integration, then Actor: search for this Actor. If it is listed, pick it and give it the input below.
- If it is not listed yet (Apify decides which Actors that dialog shows): open this Actor's page, choose Save as a new task and save the task. Back on the Integrations tab of your source Actor, choose Connect Saved tasks, pick that task and paste the input below into Input JSON overrides.
In both cases, this is the input:
{"datasetId": "{{resource.defaultDatasetId}}","datasetField": "website","outputMode": "advertisers","profile": true,"regions": ["anywhere"]}
regions is ["anywhere"] here on purpose: the Console form drops an empty list, and a run started with no regions falls back to the default US. anywhere (also all, worldwide or global) means ads shown in any country; a list of ISO codes such as ["US", "GB"] limits the check to those countries.
Every time that Actor finishes, this one runs on its dataset: each row's website becomes one check, a URL is reduced to its domain (an e-mail address to its domain), duplicates are looked up once, and every delivered row carries source_value with the original value so the two datasets join on it. Rows without a usable value are skipped and counted in the log; a dataset with none ends the run with a status message and no charge. The same works by hand on any dataset of your account: pick it in datasetId and name the field in datasetField (domain, url, company_domain, or a nested contact.website). queries is optional when datasetId is set; both are combined. Always set datasetId in the integration input: it is the field that grants the run permission to read the dataset. The run's charge limit (maxTotalChargeUsd) still caps what a large dataset can cost: 1,000 websites checked with profiles cost at most $0.005 + 1,000 x $0.002 + $0.01 for each one that runs ads (the profile part from 8 November 2026).
Use it from Clay, n8n, Make or Zapier (one run per row)
In Clay, add the Run Apify Actor enrichment to your table, connect your own Apify API key, select this Actor and paste this input, replacing DOMAIN with the column that holds the company domain:
{ "queries": ["DOMAIN"], "regions": [], "outputMode": "advertisers", "profile": true }
Clay starts one run per row, so each company costs $0.007 for the check (the start fee plus one row) and $0.017 when it turns out to run ads and the profile is on (the profile event is billed from 8 November 2026; until then it is free); a company with no ads costs $0.007 either way. The row comes back with has_ads, total_ads_min, total_ads_max, advertisers_found and, with the profile, active_last_30_days, latest_ad_last_shown, the formats and sample_ads with preview links, ready to use as columns. The same input works in the Apify nodes of n8n, Make and Zapier. To enrich a whole list in one run instead, put the list in queries (or point datasetId at it) and pay the start fee once.
Why this Actor
- Advertiser check mode. Screen a list of domains or brands in one run: one row per query saying whether the advertiser runs Google ads at all, with Google's own estimated range of active ads (for example 60,000 to 70,000 for shopify.com in October 2026) and every verified advertiser found behind the domain. Add
profile: truefor formats, dates, activity in the last 30 days and sample previews on the same row, from the same request. - Integration-ready. Add it on the Integrations tab of a lead-list scraper (Google Maps, company directories) and every website in that run's dataset is checked as soon as the run finishes, with
source_valueon each row for the join. Any dataset of your account works too. - Three ways to target. A brand name (
Nike), a domain (nike.com) or a Google advertiser ID (AR18378488041124659201). A Transparency Center URL works too. Names are resolved to the advertiser with the most ads among the matches (verified in your requested region when possible); if that advertiser runs nothing in your regions, the next match is tried. Domains return every advertiser using the domain. - Region filter that reduces what you pay. Pass ISO country codes (
US,GB,BR) and only ads shown there come back, so you are not charged for creatives you filtered out afterwards. - Dates and lifetime on every row.
first_shown,last_shownanddays_showncome straight from the Center, so you can tell a campaign that has run for 300 days from one launched yesterday. - Per-country activity on demand. Turn on
includeDetailsto get, for each creative, the list of countries it ran in with first and last dates per country, plus every preview variation. One extra request per ad, priced as its own event. - Built for schedules. Turn on
onlyNewand each run returns only creatives you have not received before, per query and region set. A daily run reports new campaigns instead of handing you the same list twice and charging for it again. - Fast and cheap to run. Pure HTTP against the Center's own JSON endpoints. In our benchmark, 100 ads across three advertisers took 10 seconds and cost half a cent of platform usage. 150 consecutive searches from one Apify server returned 150 successes with no throttling.
- Honest billing.
maxAdsPerQueryis respected exactly. A run that delivers nothing is not charged at all, not even the start fee.
What you get
Creatives (default)
{"type": "creative","query": "nike.com","advertiser_id": "AR16735076323512287233","advertiser_name": "Nike, Inc.","domain": "nike.com","creative_id": "CR02394569508766351361","format": "image","preview_url": "https://tpc.googlesyndication.com/archive/simgad/16786811858631500832","image_url": "https://tpc.googlesyndication.com/archive/simgad/16786811858631500832","video_url": null,"youtube_id": null,"first_shown": "2025-10-22T15:06:43Z","last_shown": "2026-09-03T00:32:17Z","days_shown": 308,"transparency_url": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR02394569508766351361?region=anywhere","scraped_at": "2026-09-03T01:00:09Z"}
format is image, text (text and responsive ads, delivered as a rendered preview link) or video. With includeDetails each row also carries regions (one entry per country with first_shown and last_shown), regions_count, variants and variants_count.
Advertiser check (outputMode: "advertisers")
{"type": "advertiser","query": "shopify.com","advertiser_id": "AR01625195283841286145","advertiser_name": "Shopify Inc.","domain": "shopify.com","has_ads": true,"total_ads_min": 70000,"total_ads_max": 80000,"advertisers_found": [{"advertiser_id": "AR01625195283841286145", "advertiser_name": "Shopify Inc.", "domain": "shopify.com"}],"regions": [],"transparency_url": "https://adstransparency.google.com/advertiser/AR01625195283841286145?region=anywhere","scraped_at": "2026-09-03T01:00:01Z"}
total_ads_min and total_ads_max are the range Google itself reports for the advertiser, not a count of rows this Actor fetched. regions echoes the country codes the check was limited to (empty = anywhere).
Advertiser check with profile (profile: true)
The same row, plus the profile fields. Real run, nike.com in the US, 2026-10-24:
{"type": "advertiser","query": "nike.com","advertiser_id": "AR16735076323512287233","advertiser_name": "Nike, Inc.","domain": "nike.com","has_ads": true,"total_ads_min": 8000,"total_ads_max": 9000,"advertisers_found": [{"advertiser_id": "AR16735076323512287233", "advertiser_name": "Nike, Inc.", "domain": "nike.com"},{"advertiser_id": "AR18378488041124659201", "advertiser_name": "Nike Retail BV", "domain": "nike.com"},{"advertiser_id": "AR11154049584043393025", "advertiser_name": "INITIATIVE MEDIA B.V.", "domain": "nike.com"}],"regions": ["US"],"transparency_url": "https://adstransparency.google.com/advertiser/AR16735076323512287233?region=anywhere","scraped_at": "2026-10-24T20:26:30Z","ads_sampled": 100,"format_image_count": 97,"format_text_count": 3,"format_video_count": 0,"oldest_ad_first_shown": "2021-10-25T07:00:00Z","newest_ad_first_shown": "2026-08-16T06:37:10Z","latest_ad_last_shown": "2026-10-24T20:07:41Z","active_last_30_days": true,"ads_active_last_30_days": 100,"longest_running_days": 1786,"sample_ads": [{"creative_id": "CR08716528615610646529", "format": "image", "preview_url": "https://tpc.googlesyndication.com/archive/simgad/3285937927343466209", "first_shown": "2022-12-01T08:00:00Z", "last_shown": "2026-10-24T19:56:50Z", "transparency_url": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR08716528615610646529?region=anywhere"},{"creative_id": "CR10598542018672066561", "format": "image", "preview_url": "https://tpc.googlesyndication.com/archive/simgad/11908749740924118865", "first_shown": "2022-11-30T14:48:01Z", "last_shown": "2026-10-24T19:53:54Z", "transparency_url": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR10598542018672066561?region=anywhere"}],"profile_basis": "the 100 most recent ads the Transparency Center lists for this query in US"}
The example is shortened: the run found six advertisers behind nike.com and returned three sample ads. The omitted first sample is a text ad last shown at 20:07:41Z (the latest_ad_last_shown value) whose preview link is a long script URL. A query with no ads gets the profile fields at zero and null, with profile_basis saying so, and no profile charge.
Input
| Field | What it does |
|---|---|
queries | Brand names, domains or advertiser IDs, one per line. Required unless datasetId is set. |
regions | ISO country codes. Empty or ["anywhere"] = ads shown anywhere. Default ["US"]. |
outputMode | creatives (one row per ad) or advertisers (one row per query: the check). |
profile | Advertiser check mode only. Adds the advertiser profile to each row, from the same page the check reads. Charged as advertiser-profile only when the check found ads. |
maxAdsPerQuery | Creatives mode. Hard cap per query. Default 100; raise it for large advertisers (tens of thousands of creatives). |
formats | Creatives mode. Keep only image, text and/or video. Filtered rows are not charged. |
includeDetails | Creatives mode. Adds per-country dates and preview variations to every creative. One extra request per ad, charged as ad-detail. |
onlyNew | Creatives mode. Only creatives not delivered by earlier runs of the same query and regions. History is kept for 180 days in your own account. |
proxyConfiguration | Off by default. The Center answers Apify servers directly. Configure a proxy here only if you want every request to go through it from the start. |
autoProxyFallback | On by default. A query refused on the direct connection even after retries is retried once through Apify Proxy (datacenter) before the Actor gives up on it. Turn off to fail fast. |
datasetId | Integration mode. A dataset whose rows hold the queries: set to {{resource.defaultDatasetId}} when the Actor runs as an integration of another Actor, or pick any dataset of your account. Combined with queries. |
datasetField | Integration mode. The row field that holds the domain, brand name or advertiser ID; dots reach a nested field. Default website. |
A minimal creatives run:
{ "queries": ["nike.com"], "regions": ["US"], "maxAdsPerQuery": 100 }
The input is forgiving where the platform lets it be: region codes may be lowercase, UK, USA and common country names such as Brazil or Germany are understood, an unknown region code is skipped with a warning as long as one valid code remains, and queries may hold Transparency Center URLs or {"url": ...} objects (the startUrls convention). The platform itself rejects wrong field types before the run starts, so a malformed call costs nothing. Only an input with nothing to look up, whose region codes are all unknown, or whose datasetId cannot be read fails, and the message says what to fix.
When a run returns nothing
The Actor separates "something broke" from "there was nothing to return":
- Every query refused by the Center even after retries: the run fails with a message, so a schedule notices.
- Creatives mode: no advertiser matched a name, or the advertiser has no ads in the requested regions, or
onlyNewfound nothing new: the run succeeds with a status message explaining why, and nothing is charged. - Advertiser check mode: a domain with no ads is still a delivered
has_ads: falserow, charged as one check. Only a name that matches no advertiser or a query the Center refuses yields no row, and then nothing is charged for it. - Integration mode: a dataset with no usable value in
datasetFieldends the run as succeeded with a status message, and nothing is charged; a dataset that cannot be read fails the run with the reason.
Brand names are ambiguous in the Center (dozens of verified advertisers can share a name). For precision, prefer the domain or the advertiser ID; both are shown on the public Transparency Center page.
Notes and limits
- Ad text is not extracted. Text and responsive ads are delivered as a rendered preview link (
preview_url), which the Center serves as a script, not as data. Image ads carry a direct image URL; video ads carry the video preview and the YouTube ID when the video is hosted there. - A check reads one page of the Center (20 ads, 100 with
profile), soadvertisers_foundlists the advertisers seen on that page and the profile describes up to 100 of the most recent ads, not the whole catalogue.total_ads_minandtotal_ads_maxare Google's estimate for the whole catalogue. - The Center rate-limits by IP. From Apify servers we measured 150 consecutive searches without a single refusal; a residential IP hitting the same endpoints from a laptop got throttled after a few dozen requests. The Actor backs off and retries on throttling, rotates IPs when a proxy is configured, and retries a query refused on the direct connection once through Apify Proxy (datacenter) before failing the run. Bursts of hundreds of runs from one account can still be refused for a while: space the runs out or configure a proxy from the start.
- Data comes from Google's public Transparency Center as it is at run time. Google's estimated ad counts are ranges, not exact numbers.
Pricing: what a run actually costs
Pay per event. A run that delivers nothing costs nothing.
| Event | Price | When |
|---|---|---|
| Actor start | $0.005 | Once per run, right after the first row is stored |
Ad (ad) | $0.0015 per creative on the free plan, down to $0.0009 on higher plans | Every creative row delivered |
Ad detail (ad-detail) | $0.002 | Every creative enriched with includeDetails |
Advertiser check (advertiser) | $0.002 | Every advertiser row delivered (a has_ads: false row included) |
Advertiser profile (advertiser-profile) | $0.01 | Every advertiser row delivered with profile: true when the check found ads |
The advertiser profile event is billed from 8 November 2026 (UTC). Until then, rows with profile: true are delivered at no extra charge.
Examples: 100 ads for one advertiser, no details, costs $0.005 + 100 x $0.0015 = $0.155 on the free plan; the same 100 ads with details cost $0.355. Checking 1,000 domains in one run costs $0.005 + 1,000 x $0.002 = $2.005; with profiles, add $0.01 for each domain that turned out to run ads. Platform usage on top of that was half a cent in our benchmark run.
Changelog
- 0.1.7 (2026-10-27): README only, same code as 0.1.6. The integration section now describes both ways to connect this Actor on the Integrations tab of another Actor: through Add integration when it is listed there, or through Save as a new task plus Connect Saved tasks with Input JSON overrides. Its example uses
"regions": ["anywhere"], because the Console form drops an empty list and the run would fall back toUS. - 0.1.6 (2026-10-27): integration mode.
datasetId(withdatasetField, defaultwebsite) takes the queries from the dataset of another Actor's run, so this Actor can be added on the Integrations tab of a lead-list scraper or run by hand on any dataset of the account; a website URL is reduced to its domain, duplicates are looked up once and every row carriessource_valuefor joining the two datasets.queriesis optional whendatasetIdis set. README: how to run it after another Actor and from Clay, n8n, Make or Zapier. - 0.1.5 (2026-10-27): the advertiser profile is charged only while its
advertiser-profileevent carries a price in the run; until then the profile is delivered at no charge, with no charge attempt and no warning in the run log, and the status message says how many profiles went out that way. When the run charge limit (maxTotalChargeUsd) stops a run, the status message names the queries that were not processed and, in creatives mode, says that the last query may be incomplete. The "Advertiser checks" view now also shows the advertisers found, the oldest and newest first shown dates and the sample ads. - 0.1.4 (2026-10-24): advertiser profile (
profile: truein check mode): ads by format, oldest and newest dates, activity in the last 30 days, longest running ad and sample previews on the same row, from the same request, as its ownadvertiser-profileevent, billed from 8 November 2026. "Advertiser checks" view in the dataset tab. Fixed: an advertiser check with a regions filter (the defaultUSincluded) failed while storing its row, because the dataset schema only allowed the per-country objects of creative rows; the schema now accepts the region codes the check rows carry. The start fee is now charged right after the first row is stored, never before, so a run whose first row cannot be stored pays nothing; the same holds forad-detail. When the run's charge limit (maxTotalChargeUsd) no longer covers a detail or a profile, the row is delivered without it and the log says so. TheonlyNewmemory is saved even when a later page is refused, so rows already delivered are never charged twice. Input synonyms (mode,country,includeProfile,maxAds) now take precedence over the defaults the platform fills in. README reorganised around the check. - 0.1.3 (2026-10-24): a query refused on the direct connection is retried once through Apify Proxy (datacenter) before the run fails (
autoProxyFallback, on by default). Forgiving regions: lowercase codes,UK,USAand common country names are understood, and an unknown code is skipped with a warning instead of failing the run when a valid one remains.queriesaccepts Transparency Center URLs and{"url": ...}objects. Clearer message when the input has nothing to look up. - 0.1 (2026-09-03): first release. Creatives by name, domain or advertiser ID; region and format filters; per-country details; advertiser check mode; onlyNew for schedules.