Google Ads Transparency Center Scraper & API avatar

Google Ads Transparency Center Scraper & API

Pricing

from $0.70 / 1,000 ad creatives

Go to Apify Store
Google Ads Transparency Center Scraper & API

Google Ads Transparency Center Scraper & API

Every Google ad an advertiser is running: creatives, formats, first/last shown, impression ranges, per-country reach. Search by domain, brand or advertiser ID. Competitor ads monitor: schedule it and get only new ads. Batch 'is this domain advertising?' checks for lead enrichment. No browser.

Pricing

from $0.70 / 1,000 ad creatives

Rating

0.0

(0)

Developer

Brenton Keller

Brenton Keller

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 hours ago

Last modified

Share

Google Ads Transparency Center Scraper

Pull every ad an advertiser is running on Google (Search, YouTube, Shopping, Maps, Play) from the Ads Transparency Center, as clean JSON/CSV. Search by domain, brand name, advertiser ID or a pasted Transparency Center URL. Filter by country, format, platform and date. Run it on a schedule with "only new ads" to get a feed of newly launched competitor creatives. Use advertiser-check mode to answer "is this company running Google Ads, and how many?" for thousands of domains at a fraction of a cent each.

No browser, no login. Talks to the Transparency Center's own data API directly with a browser-grade TLS fingerprint, paces itself under Google's rate limits and rotates proxies automatically, so runs finish fast and don't fail halfway.

Try it free: every Apify account includes free monthly usage, and 1,000 ads cost $1, so checking a competitor is free.

Competitor ads monitor: schedule it, get an alert when new ads appear

This is the highest-value way to use the actor: a daily run that returns only the ads you have not seen before, delivered to Slack or email. Three steps, no code:

  1. Create a task from this actor with the input below (one line per competitor domain or advertiser ID). Run it once; the first run seeds the list of known ads.

  2. Schedule it: in the task, open Schedule (or Console → Schedules) and pick daily or hourly. Each run costs only the new ads it finds; a quiet day costs a few requests and no results.

  3. Alerts: in the task's Integrations tab add Slack or Gmail on "run succeeded". Use the run's status message as the notification text; in monitor mode it reads 3 NEW ad(s) since last run across 5 target(s) or No new ads since last run. Slack message template (Handlebars):

    *Google Ads monitor:* {{resource.statusMessage}}
    <https://console.apify.com/storage/datasets/{{resource.defaultDatasetId}}|Open the new ads>

    For "only notify when there is something new", route the run through n8n / Make / Zapier (Apify triggers exist for all three) and filter on the dataset item count.

{
"domains": ["nike.com", "adidas.com", "onrunning.com"],
"onlyNewAds": true,
"monitorStoreName": "running-shoes-competitors",
"includeDetails": true,
"maxAdsPerQuery": 200
}

Each new ad row carries is_new: true, the creative preview URL, format, first/last shown and (with includeDetails) served countries and surfaces, so the alert is actionable: what launched, where, in which format. Use one monitorStoreName per watchlist. Works with advertiserIds, queries (brand names) and startUrls too; add region, format or surface to narrow it (e.g. only new YouTube video ads in DE).

What it costs at scale: 5 competitors × ~10 new ads/day with details = 50 × $0.004 = $0.20/day, ~$6/month; without details, $1.50/month. Compare with ad-spy subscriptions at $50–100/month.

What it does

ModeOne row perUse it for
ads (default)ad creativecompetitor creative research, ad libraries, longevity analysis (which ads run for months), creative monitoring
advertisersmatched advertiserlead enrichment / qualification: is this domain advertising on Google right now, under which account(s), roughly how many ads

Who it's for

  • Performance marketers and agencies tracking competitors' Google ads: new-creative alerts, formats, and how long each creative survives (an ad-spy tool for Google, YouTube and Shopping ads at pay-per-result prices).
  • Sales and lead-gen teams enriching prospect lists (Clay, n8n, Make, Zapier, Google Sheets) with "runs Google Ads: yes/no + volume" as a buying signal.
  • Brand and compliance teams watching for affiliates, resellers or impersonators advertising on their domain.
  • Researchers and journalists studying advertising activity by region and platform.
  • AI agents: every field is stable and typed, and the actor is exposed as an MCP tool via Apify.

Input examples

All ads for a domain, US, last 90 days, YouTube only

{
"domains": ["allbirds.com"],
"region": "US",
"surface": "YOUTUBE",
"dateFrom": "2026-06-01",
"maxAdsPerQuery": 500
}

A brand by name, with full per-country details

{
"queries": ["Nike"],
"maxAdvertisersPerQuery": 1,
"includeDetails": true
}

Paste Transparency Center URLs

{
"startUrls": [{ "url": "https://adstransparency.google.com/advertiser/AR18378488041124659201?region=GB" }]
}

Monitor by advertiser ID instead of domain (see the monitor section above for scheduling and alerts)

{
"advertiserIds": ["AR18378488041124659201", "AR16735076323512287233"],
"onlyNewAds": true,
"monitorStoreName": "footwear-competitors"
}

Lead enrichment: is each domain advertising?

{
"domains": ["allbirds.com", "warbyparker.com", "some-local-plumber.com"],
"mode": "advertisers",
"region": "US"
}

Output

ads mode

{
"creative_id": "CR04143963882324492289",
"advertiser_id": "AR18378488041124659201",
"advertiser_name": "Nike Retail BV",
"format": "TEXT",
"matched_domain": "nike.com",
"first_shown": "2026-07-22T04:31:55+00:00",
"last_shown": "2026-09-01T21:04:44+00:00",
"days_shown": 43,
"impressions": null,
"impressions_low": null,
"impressions_high": null,
"preview_url": "https://tpc.googlesyndication.com/archive/simgad/12774179880874022668",
"preview": { "script_url": "…", "iframe_url": null, "html_snippet": null, "image_url": "…" },
"ad_url": "https://adstransparency.google.com/advertiser/AR18378488041124659201/creative/CR04143963882324492289?region=anywhere",
"advertiser_url": "https://adstransparency.google.com/advertiser/AR18378488041124659201?region=anywhere",
"query": "nike.com",
"query_kind": "domain",
"region": "US",
"matched_total": { "low": 100000, "high": 200000 },
"is_new": true
}

With includeDetails: true each row also gets:

"details": {
"served_countries": ["US", "GB", "DE", "FR", "CA"],
"country_reach": [{ "country": "US", "first_served": "2026-07-22", "last_served": "2026-09-01", "impressions": null, "surfaces": [] }],
"eu_reach": { "impressions": { "low": 10000, "high": 50000 }, "first_served": "2026-07-21", "last_served": "2026-09-01" },
"variations": [ { "script_url": "…", "image_url": "…" } ],
"targeting": { "categories": { "demographics": {"included": true}, "geography": {"included": true} } },
"category": { "gcb_category_id": 10021, "vertical": 1 },
"customer_name": "Nike Retail BV",
"contains_synthetic_media": false
},
"countries": ["US", "GB", "DE", "FR", "CA"],
"surfaces": ["SEARCH", "YOUTUBE"]

Impression and spend ranges are only published by Google for EU-served ads and political ads; elsewhere they are null. Where they exist they are lifted to the top level as impressions_low / impressions_high (global) and eu_impressions_low / eu_impressions_high (EU reach from the details block), so CSV exports and the Overview table show them without digging into details. matched_total is Google's estimate of how many ads match the whole query (useful even when you cap maxAdsPerQuery).

advertisers mode

{
"query": "allbirds.com",
"query_kind": "domain",
"region": "US",
"is_advertising": true,
"advertiser_id": "AR12345678901234567890",
"advertiser_name": "Allbirds Inc",
"creatives_count_low": 1000,
"creatives_count_high": 2000,
"advertisers_on_domain": 1,
"formats_seen": ["IMAGE", "TEXT", "VIDEO"],
"last_shown": "2026-09-02T01:46:39+00:00",
"advertiser_url": "https://adstransparency.google.com/advertiser/AR12345678901234567890?region=US"
}

Domains with no ads return one row with is_advertising: false, so every input gets exactly one answer.

Advertiser-check rows for a domain

Each advertiser row for a domain carries its own ad count for that domain (creatives_count_low / creatives_count_high), the advertiser's billing country, legal_name and unverified flag from its Transparency Center profile, and the domain-wide total in domain_creatives_count_low / domain_creatives_count_high. This distinguishes the domain owner (Nike, Inc.: 7,000–8,000 ads on nike.com) from resellers and affiliates that also link to the domain (an agency with 500–600). Costs 2 extra requests per advertiser row; maxAdvertisersPerQuery caps it.

Pricing

Pay per result, no subscription:

EventPrice
Ad creative (ads mode)$1.00 per 1,000
Ad creative with full details (includeDetails)$4.00 per 1,000
Advertiser check row (advertisers mode)$2.00 per 1,000

Plus normal Apify platform usage (a few cents per thousand ads; the actor runs in 256 MB and makes one request per 40 ads). Failed targets are not charged.

Limits and notes

  • Google paginates to roughly 1,000 ads per query. Split large advertisers by format, surface or date range to get more.
  • Google keeps about 12 months of ad history.
  • A domain search returns every advertiser whose ads link to that domain, not only the domain owner. That can include resellers, affiliates and demo/test ads (example.com yields real ads from unrelated advertisers). Use advertisers mode to see who they are, or advertiserIds to pin one account.
  • Brand-name queries are resolved through Google's own suggestion index; the largest exact/prefix match is used first. Use advertiserIds for precision.
  • Ad-text (keyword) search is only available for political ads in Google's data and is not exposed here.
  • Google rate-limits by IP. Keep the default Apify proxy on for anything beyond a few hundred ads; the actor rotates sessions on every rate-limit response and backs off, so runs complete instead of failing.
  • If Google blocks every request (bot-check page or HTTP 429 after retries), the run fails with a clear error and nothing is charged. Enable Apify Proxy (residential) or raise requestDelaySeconds. If only some targets are blocked, the run succeeds and those targets get a row with an error field.
  • Rows whose detail lookup failed (details_error) are charged at the base ad rate, not the enriched rate.
  • Monitor state is per monitorStoreName (a named key-value store in your account). Do not run two monitor runs against the same store at the same time; use one store per watchlist or schedule.

Use as an MCP tool / from code

The actor is callable from any MCP client through Apify's MCP server, and from code with the Apify API. Agent pattern: keep a watchlist, call with onlyNewAds: true on a schedule, and act only on the rows that come back.

curl -X POST "https://api.apify.com/v2/acts/<username>~google-ads-transparency-center/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"domains": ["allbirds.com"], "mode": "advertisers", "region": "US"}'

This actor only reads data that Google publishes for public inspection in the Ads Transparency Center. Use it in line with Google's terms and applicable law; you are responsible for how you use the output.

Support

Open an issue on the actor page with the run ID and input. If Google changes the Transparency Center's data format, affected fields go null rather than failing the run; report which field and we will patch it. If the actor saved you time, a review helps other people find it.