# Google Ads Transparency Center Scraper - Competitor Ads Checker (`orbots/google-ads-transparency-scraper`) Actor

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.

- **URL**: https://apify.com/orbots/google-ads-transparency-scraper.md
- **Developed by:** [Orbots](https://apify.com/orbots) (community)
- **Categories:** SEO tools, Automation, Integrations
- **Stats:** 9 total users, 9 monthly users, 80.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 ad (creative row)s

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 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:

```json
{
  "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 your `regions`. Empty `regions` means anywhere, so a domain can be `false` for `["US"]` and `true` for `[]`.
- How big is it? `total_ads_min` and `total_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:

1. **Add integration**, then **Actor**: search for this Actor. If it is listed, pick it and give it the input below.
2. 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:

```json
{
  "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:

```json
{ "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: true` for 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_value` on 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_shown` and `days_shown` come 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 `includeDetails` to 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 `onlyNew` and 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.** `maxAdsPerQuery` is respected exactly. A run that delivers nothing is not charged at all, not even the start fee.

### What you get

#### Creatives (default)

```json
{
  "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"`)

```json
{
  "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:

```json
{
  "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:

```json
{ "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 `onlyNew` found 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: false` row, 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 `datasetField` ends 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`), so `advertisers_found` lists the advertisers seen on that page and the profile describes up to 100 of the most recent ads, not the whole catalogue. `total_ads_min` and `total_ads_max` are 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 to `US`.
- **0.1.6** (2026-10-27): integration mode. `datasetId` (with `datasetField`, default `website`) 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 carries `source_value` for joining the two datasets. `queries` is optional when `datasetId` is 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-profile` event 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: true` in 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 own `advertiser-profile` event, billed from 8 November 2026. "Advertiser checks" view in the dataset tab. Fixed: an advertiser check with a regions filter (the default `US` included) 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 for `ad-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. The `onlyNew` memory 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`, `USA` and common country names are understood, and an unknown code is skipped with a warning instead of failing the run when a valid one remains. `queries` accepts 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.

# Actor input Schema

## `queries` (type: `array`):

One entry per line: a brand name (Nike), a domain (nike.com) or a Google advertiser ID (AR18378488041124659201). A Transparency Center URL also works. Names are resolved to the best-matching advertiser; domains return every advertiser using that domain. Optional when datasetId is set (integration mode): both lists are combined.

## `regions` (type: `array`):

Country codes (ISO 3166-1 alpha-2: US, GB, BR, DE...). Only ads shown in these countries are returned. Leave empty for ads shown anywhere. Case does not matter; UK, USA and common country names (Brazil, Germany) are understood; an unknown code is skipped with a warning when at least one valid code remains.

## `maxAdsPerQuery` (type: `integer`):

Creatives mode only. Hard cap per advertiser, domain or name. The Actor stops at exactly this number and never charges beyond it. Default 100; raise it for large advertisers (tens of thousands of creatives).

## `formats` (type: `array`):

Creatives mode only. Keep only these formats. Rows filtered out are not charged.

## `includeDetails` (type: `boolean`):

Creatives mode only. Fetches the detail record of every creative: first and last shown date per country and all preview variations. One extra request per ad, charged as an ad-detail event.

## `outputMode` (type: `string`):

Creatives = one row per ad. Advertiser check = one row per query saying whether the advertiser runs Google ads, with Google's estimated ad count range; ideal for screening a list of domains.

## `profile` (type: `boolean`):

Advertiser check mode only. Adds to each row, from the same page the check already reads (no extra request): ads sampled, ads by format, oldest and newest first shown dates, latest last shown date, whether any ad was shown in the last 30 days, the longest running ad in days and up to 3 sample previews. Charged as an advertiser-profile event only when the check found ads.

## `onlyNew` (type: `boolean`):

Creatives mode only. Built for schedules. The Actor remembers which creatives it already delivered for each query and region set, and returns only the ones it has not sent you before, so a daily run reports new campaigns instead of repeating the whole list and charging for it again. History is kept for 180 days in your own account.

## `proxyConfiguration` (type: `object`):

Not required: the Transparency Center answers Apify servers directly, and a query refused on the direct connection is retried once through Apify Proxy (datacenter) on its own (see autoProxyFallback). Configure a proxy here only if you want every request to go through it from the start.

## `autoProxyFallback` (type: `boolean`):

On by default. When the Transparency Center refuses a query on the direct connection even after retries, the Actor retries that query once through Apify Proxy (datacenter) before giving up on it. Turn off to fail fast instead.

## `datasetId` (type: `string`):

Optional. A dataset whose rows carry the domains, brand names or advertiser IDs to look up, one per row, in the field named in datasetField. Made for running this Actor as an integration of another Actor (its Integrations tab, Add integration, Actor): set it to {{resource.defaultDatasetId}} there and every row of the finished run becomes one query. Any dataset of your account works too. queries is optional when datasetId is set; both are combined.

## `datasetField` (type: `string`):

Integration mode only. The field of each dataset row that holds the domain, brand name or advertiser ID: website (Google Maps scrapers), domain, url, company_domain. A nested field works with dots (contact.website). A website URL is reduced to its domain, an e-mail address to its domain, duplicates are looked up once, and rows without a usable value are skipped and counted in the log.

## Actor input object example

```json
{
  "queries": [
    "nike.com"
  ],
  "regions": [
    "US"
  ],
  "maxAdsPerQuery": 100,
  "formats": [
    "image",
    "text",
    "video"
  ],
  "includeDetails": false,
  "outputMode": "creatives",
  "profile": false,
  "onlyNew": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "autoProxyFallback": true,
  "datasetField": "website"
}
```

# Actor output Schema

## `results` (type: `string`):

Every row collected by the run, in delivery order. Each row carries a "type" field: creative or advertiser.

## `creatives` (type: `string`):

One row per ad: advertiser, domain, format, preview asset, first and last shown dates, days active, and a link to the public Transparency Center page.

## `creativesCsv` (type: `string`):

The same ads as a spreadsheet-ready CSV.

## `advertisers` (type: `string`):

Advertiser-check rows: whether each query runs Google ads, with Google's estimated ad count range, every advertiser found behind the query and, with profile: true, the advertiser profile.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "nike.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("orbots/google-ads-transparency-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "queries": ["nike.com"] }

# Run the Actor and wait for it to finish
run = client.actor("orbots/google-ads-transparency-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "nike.com"
  ]
}' |
apify call orbots/google-ads-transparency-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,orbots/google-ads-transparency-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/sJrZ5bg8nofpBZEZM/builds/C8ZpHNvck3GHGbTSQ/openapi.json
