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. Monitor changes in Google's result window. Batch 'is this domain advertising?' checks for lead enrichment. No browser.

Run on Apify Pricing API docs

Categories: MARKETING, LEAD_GENERATION, AGENTS. Pay per result, no subscription; Apify's free plan includes $5 of monthly usage.

Run it from the command line

curl -sS -X POST "https://api.apify.com/v2/acts/brenton8907~google-ads-transparency-center/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"domains": ["nike.com"], "mode": "ads", "region": "ANYWHERE", "format": "ALL", "surface": "ALL", "maxAdsPerQuery": 200}'

Run it from Python

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("brenton8907/google-ads-transparency-center").call(run_input={
  "domains": [
    "nike.com"
  ],
  "mode": "ads",
  "region": "ANYWHERE",
  "format": "ALL",
  "surface": "ALL",
  "maxAdsPerQuery": 200
})
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

Use it as an MCP tool (Claude, Cursor, any MCP client)

The actor is listed in the official MCP registry as io.github.brenton-keller/google-ads-transparency-center and served by Apify's hosted MCP server:

{
  "mcpServers": {
    "google-ads-transparency-center": {
      "url": "https://mcp.apify.com/?tools=brenton8907/google-ads-transparency-center",
      "headers": {
        "Authorization": "Bearer YOUR_APIFY_TOKEN"
      }
    }
  }
}

Pricing (pay per event)

eventwhatpricedetails
ad-recordAd creative$0.0010One ad creative row: advertiser, format, preview URL, first/last shown, days shown, impression and spend ranges, matched domain.
enriched-ad-recordEnriched ad creative$0.0040One ad creative row with full details attached: per-country impression ranges, surfaces, targeting, category. One extra request per ad.
advertiser-recordAdvertiser check$0.0020One advertiser summary row (advertiser-check mode): advertiser IDs matched for a domain or brand, creative count range, verification status. One request per query.

Documentation

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 newly observed ads" to track changes in Google's result window. 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, track Google's result window

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 creative IDs not previously observed in the capped result window; 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 reports newly observed result-window ads or that none were observed. Slack message template (Handlebars):

*Google Ads monitor:* {{resource.statusMessage}} <https://console.apify.com/storage/datasets/{{resource.defaultDatasetId}}|Open the newly observed 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 newly observed row carries is_new: true, first_seen_by_monitor, the creative preview URL, format, first/last shown and (with includeDetails) served countries and surfaces. This means newly observed, not necessarily newly launched. Google's capped top-N result window can reorder between runs, so a creative first shown months or years ago can enter the window and appear for the first time. Use first_shown to identify likely launches; narrow by advertiser ID, region, format, surface or date to make the window more stable. Use one monitorStoreName per watchlist.

What it costs at scale: 50 newly observed ads/day with details = 50 × $0.004 = $0.20/day, ~$6/month; without details, $1.50/month. Result-window reordering can increase this count on broad or heavily capped queries.

What it does

Mode One row per Use it for
ads (default) ad creative competitor creative research, ad libraries, longevity analysis (which ads run for months), creative monitoring
advertisers matched advertiser lead enrichment / qualification: is this domain advertising on Google right now, under which account(s), roughly how many ads

Who it's for

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:

Event Price
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

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.