# Google Ads Transparency Scraper (`dami_studio/google-ads-transparency-scraper`) Actor

Google Ads Transparency Center scraper by domain, advertiser name or ID: see the ads a brand runs. Each row has the format, first and last shown dates, how many days it served, the landing domain and a preview link. Per-country impressions are optional. $0.60 per 1,000 ads.

- **URL**: https://apify.com/dami_studio/google-ads-transparency-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Marketing, Lead generation, Business
- **Features:** Limited permissions
- **Stats:** 9 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.57 / 1,000 google ad results

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 for a landing domain, an advertiser name or ID, one row per ad creative**: the
format, when Google first and last saw it serving, on how many days it served, and a link that opens
the ad itself. Ads Transparency Center links work as pasted too.

What it cannot give you, said up front: money. No spend or budget. Impressions arrive as wide bands like "up to 1,000", per
country, and only when you ask for them.

| | |
|---|---|
| **Input** | Advertiser domains, names, IDs, or Ads Transparency links |
| **Output** | One row per ad creative, or one per advertiser |
| **Ceiling** | 20,000 rows per run |
| **Account needed** | None, and no Google API key |
| **Price** | $0.60 per 1,000 ads on the Free plan, a little less on paid plans. The free plan's $5 a month covers about 8,300 |

### 🔍 What Google Ads Transparency Scraper does

The Ads Transparency Center is the public archive Google publishes of the ads running through its
network. This reads it.

**Four ways in.** A domain catches the advertiser accounts pointing at it, which is the easiest
start. A name is resolved to an advertiser ID first. An ID pins you to one entity. A link from the
site works as pasted.

**Two shapes of row.** By default you get creatives. Switch `listAdvertisersOnly` on with a name and
you get the matching advertisers instead, with their IDs, verified country and a rough ad-count
band, which is how you find the right entity before spending anything.

**Narrow it, or add to it.** `region`, `adFormat` and `platform` (Search, YouTube, Shopping, Maps or
Play) cut the list down. `includeRegionStats` adds the per-country breakdown, and
`includeAdvertiserDetails` the advertiser's verified legal name and country.

Creatives shared between two of your targets are deduplicated, so you are not billed twice for the
same ad.

### 📋 What data you get from each Google ad

| What you get | Field |
|---|---|
| The advertiser and the creative's ids | `advertiserId`, `advertiserName`, `creativeId` |
| Text, image or video, as Google files it | `adFormat` |
| When Google first and last saw it serve, and on how many days | `firstShownAt`, `lastShownAt`, `daysShown` |
| The landing page's domain, when Google shows it | `landingDomain` |
| A picture of the ad, or the renderer Google's site embeds | `previewImageUrl`, `previewIframeUrl` |
| Links back into the Ads Transparency Center | `creativeUrl`, `advertiserUrl` |
| Which of your targets found it, the region asked and its position | `queriedBy`, `region`, `position` |
| Per country, with region stats on: impression band, first and last date, and where it showed | `regionStats` |
| With details on: the advertiser's verified legal name and country | `advertiserLegalName`, `advertiserCountry` |
| On advertiser rows: verified country and a band for how many ads they run | `advertiserCountry`, `adCountLower`, `adCountUpper` |

### ▶️ How to scrape Google Ads Transparency

1. Open
   [Google Ads Transparency Center Scraper](https://apify.com/dami_studio/google-ads-transparency-scraper)
   and click **Try for free**.
2. Put a landing domain into **Advertiser domains**, replacing the example.
3. Set **Region** to a country code if you want one market, and **Max results** to what you actually
   need.
4. Turn on **Include per-region impressions** only if you need the country breakdown, then click
   **Start**.
5. Download the dataset as JSON, CSV or Excel, or read it from the Apify API.

Run it with everything empty and you get one labelled sample row, not charged.

### 💰 How much does it cost to scrape Google Ads Transparency?

**$0.60 per 1,000 ads**, which is $0.0006 a row on the Free plan. Paid plans pay a little less: $0.59 on Starter, $0.58 on Scale and $0.57 on Business.
On the free plan, the $5 Apify gives you each month covers about 8,300 ads.

An advertiser row costs the same as a creative row. `maxItems` caps the total, so it also caps what
a run can bill.

Not charged: the sample row, every diagnostic row, a target that turns out to have no ads, and
creatives deduplicated across two of your targets.

### 📥 What you give it

Fill in at least one of the first four.

```json
{
  "advertiserDomains": ["nike.com"],
  "region": "US",
  "adFormat": "any",
  "maxItems": 100
}
```

| Field | Default | What it is |
|---|---|---|
| `advertiserDomains` | none, the box starts at `nike.com` | Landing-page domains. Catches the advertiser accounts pointing there. |
| `advertiserNames` | none | Names as Google verified them, like `Nike, Inc.`. Resolved to an ID, then scraped. |
| `advertiserIds` | none | IDs like `AR16735076323512287233`, readable off any Ads Transparency link. |
| `startUrls` | none | Advertiser or creative permalinks pasted from the site. |
| `region` | `anywhere` | Two-letter country code, or `anywhere`. It changes the result set, not just the labels. |
| `adFormat` | `any` | `any`, `IMAGE`, `TEXT` or `VIDEO`. |
| `platform` | `any` | `any`, `SEARCH`, `YOUTUBE`, `SHOPPING`, `MAPS` or `PLAY`. Only ads Google showed there, and Google does the narrowing. One platform per search. Not with `listAdvertisersOnly`. |
| `maxItems` | `100` | Total rows across every target, up to 20,000. It is also the most a run can bill you. |
| `listAdvertisersOnly` | off | With names filled in, return the advertisers instead of their creatives. |
| `includeRegionStats` | off | Per-country impression bands and surface split. One extra request per ad. |
| `includeAdvertiserDetails` | off | The advertiser's verified legal name and country, looked up once each. |
| `proxyConfiguration` | leave it empty | Optional. Your own servers in `proxyUrls` are used exactly as given and take priority. |
| `egressMode` | `auto` | Advanced. Leave this on Auto. If a run stops with a `RATE_LIMITED` row, wait a few minutes and run it again. |

### 📤 What you get back

A real creative row from a run on 24 October 2026. It is a Search text ad, and like nearly every text
ad it comes as a picture:

```json
{
  "ok": true,
  "resultType": "creative",
  "advertiserId": "AR16735076323512287233",
  "advertiserName": "Nike, Inc.",
  "creativeId": "CR09764113126705332225",
  "adFormat": "TEXT",
  "firstShownAt": "2023-11-16T21:41:39.640Z",
  "lastShownAt": "2026-10-24T05:33:57.550Z",
  "regionsShownCount": 906,
  "landingDomain": "nike.com",
  "previewImageUrl": "https://tpc.googlesyndication.com/archive/simgad/271805870859790397",
  "previewIframeUrl": null,
  "previewText": null,
  "creativeUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR09764113126705332225?region=anywhere",
  "advertiserUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233?region=anywhere",
  "queriedBy": "domain:nike.com",
  "region": "anywhere",
  "position": 3,
  "scrapedAt": "2026-10-24T05:59:37.026Z",
  "daysShown": 906
}
```

| Field | How to read it |
|---|---|
| `firstShownAt`, `lastShownAt` | When Google first and last observed the creative serving. A `lastShownAt` from the last day or two means it is live now. |
| `adFormat` | `TEXT`, `IMAGE` or `VIDEO`, as Google files the ad. A Search ad like the one above is `TEXT`. |
| `daysShown` | How many days Google saw the ad serve: the ad above served on 906 days. |
| `regionsShownCount` | The same number as `daysShown`, under its first name, kept for pipelines that already read it. Despite the name it counts days, not regions or countries. |
| `previewImageUrl` | A direct archive address of a picture of the ad. Nearly every text ad carries it, and so do many image ads. |
| `previewIframeUrl` | The renderer Google's own site embeds. Video ads carry this instead, and so do some image ads and the odd text ad. |
| `previewText` | Expect `null`. It only fills when Google sends an ad as plain words, and none of the text ads we checked came that way: Google sends a text ad as a picture of it, or now and then as the renderer link. |
| `landingDomain` | The landing page's domain when Google exposes it, and `null` when it does not. |
| `regionStats` | With `includeRegionStats` on: `regionCode`, `regionName`, `impressionsLower`, `impressionsUpper`, `firstShownDate`, `lastShownDate` and `surfaces` per country. |

### 🧾 Reading the output

| Row | How to spot it | Charged |
|---|---|---|
| An ad or an advertiser | `ok: true`, with a `resultType` | yes |
| The sample row | `_sample` present | no |
| A diagnostic | `_diagnostic` present, with an error code | no |

| Code | What it means |
|---|---|
| `NO_ADS` | That target has no ads in that region. The row suggests trying `region: "anywhere"`. |
| `NO_ADVERTISER_MATCH` | No verified advertiser matches that name. Try the domain instead. |
| `NO_ADVERTISER_NAMES` | `listAdvertisersOnly` is on but no names were given. |
| `BAD_REGION` | That region code is not one Google recognises. The run stops here. |
| `BAD_DOMAIN`, `BAD_ADVERTISER_ID`, `BAD_URL` | One of your inputs is not in a usable shape. |
| `RATE_LIMITED` | Google throttled the run. Re-run it. |
| `API_ERROR`, `HTTP_ERROR`, `BAD_BODY` | Google answered, but not with usable data. |
| `NETWORK` | Google was unreachable or the response never finished. |
| `TIME_LIMIT` | The run got close to its time limit and stopped on its own. The ads delivered before that are complete. Give the run more time, or ask for fewer ads, to get the rest. |
| `UNEXPECTED_ERROR` | The run stopped early on an unexpected error. The results before this row are kept. |

A diagnostic never fails the run, `TIME_LIMIT` included: a run the time limit stopped before any ad came back still ends as succeeded, with an amber status message.

The Overview table shows `previewImageUrl`, which text ads and many image ads carry, so video ads and
some image ads look like they have no preview there. Read `previewIframeUrl` in the JSON for those.

### 💡 What people use it for

- Seeing which ads a competitor is running this week, and which creatives they keep.
- Judging what works for them: an ad that has been serving for two years is an ad that pays.
- Finding a company's other advertising entities, since one domain often sits under several verified
  advertisers per market.
- Mapping which countries a campaign actually ran in, with `includeRegionStats`.

From a brand name to its ads on Google and Meta, in three runs:

1. Put the brand into `advertiserNames` with `listAdvertisersOnly` on, and pick the right
   `advertiserId` from the list.
2. Run that ID in `advertiserIds` with `includeRegionStats` on, to see each creative and where it
   ran.
3. Put the same brand into [Meta Ad Library Scraper](https://apify.com/dami_studio/meta-ads-library-scraper)'s
   `searchTerms` for its Facebook and Instagram ads.

### 🚧 What it does not do

- **No spend, no budgets.** Impressions are wide bands.
- **No targeting criteria for political ads.** Election ads show extra data in the site's own
  interface; the rows here carry the same fields as any other ad.
- **No ad copy as text, not even on text ads.** The headline and description are in the picture at `previewImageUrl`, not in a field you can
  search. Video and rich media come as the renderer link, not a transcript.
- **`daysShown` counts days, not places.** Use `includeRegionStats` for the countries.
- **A creative permalink is found by scanning that advertiser's first `maxItems` creatives**, so a
  creative further down their list comes back as `NO_ADS` even though it exists. Raise `maxItems`, or
  query the advertiser instead.
- **`adFormat` filters after reading**, so asking for a rare format on a big advertiser takes a while.
  It does not cost more, because you pay for rows that come back.
- **One platform per search.** YouTube and Maps
  together take two runs.
- **It cannot find an advertiser who has never advertised on Google.** An empty answer is a real
  answer, and it is not charged.
- It is not an official Google tool. Dami's Studio is independent and is not affiliated with or endorsed by Google, or by any other company named on this page.

### 🧭 Which Google or ad library scraper do you need?

| If you want | Use |
|---|---|
| The web results page for a keyword: organic, ads, People Also Ask | [Google Search Results Scraper](https://apify.com/dami_studio/google-search-results-scraper) |
| What a search box suggests as people type | [Keyword Autocomplete Scraper](https://apify.com/dami_studio/keyword-autocomplete-scraper) |
| Interest in a keyword over time and by region | [Google Trends Scraper](https://apify.com/dami_studio/google-trends-scraper) |
| News articles with the publisher's real link | [Google News Scraper](https://apify.com/dami_studio/google-news-scraper) |
| Image results and the pages they sit on | [Google Images Scraper](https://apify.com/dami_studio/google-images-scraper) |
| The ads a brand runs on Google | This one |
| Facebook and Instagram ads by keyword or Page | [Meta Ad Library Scraper](https://apify.com/dami_studio/meta-ads-library-scraper) |
| LinkedIn ads, naming the company in the ad and the one paying | [LinkedIn Ads Scraper](https://apify.com/dami_studio/linkedin-ads-scraper) |

### ❓ Questions people ask

#### Do I need a Google account or an API key?

No. The archive is public and there is nothing to sign in to.

#### How do I find an advertiser ID?

Put the company name in `advertiserNames` and turn on `listAdvertisersOnly`. You get the matching
advertisers with their IDs and rough ad counts.

#### Why do several advertisers come back for one domain?

Large companies run separate accounts per market or per legal entity, and Google verifies each one.
A domain covers them together; an ID pins you to one.

#### Can I filter by country?

Yes. `region` changes the result set, not just the labels, so the same advertiser returns very
different counts for `US` and `GB`.

#### Can I call it from code or connect it to an AI assistant?

The [API tab](https://apify.com/dami_studio/google-ads-transparency-scraper/api/python) has code for Python,
JavaScript and the CLI. MCP clients like Claude and ChatGPT use
`https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/google-ads-transparency-scraper`; coding assistants can
load [our skill
file](https://api.apify.com/v2/key-value-stores/BTBHU3DdiuoF4JOsK/records/apify-search-app-stores-SKILL.md). All three
bill your Apify account at the same price.

#### Is scraping the Ads Transparency Center legal?

The archive is published deliberately, for public inspection. Apify's write-up on
[the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) is a good starting
point, and we are not lawyers.

### 🆘 If something breaks

Open the **Issues** tab on the actor page. Send the domain or advertiser ID, the region and the run
ID. The error code on the diagnostic row usually names the problem on its own.

# Actor input Schema

## `advertiserDomains` (type: `array`):

Landing-page domains to look up, for example nike.com. This is the easiest way in: you get the Google ads whose landing page sits on that domain, across its advertiser accounts.

## `advertiserNames` (type: `array`):

Advertiser names as they appear in Google's verification records, for example "Nike, Inc.". Each name is resolved to its advertiser ID and then scraped. Turn on "List advertisers only" to get the matching advertisers instead of their ads.

## `advertiserIds` (type: `array`):

Google advertiser IDs such as AR16735076323512287233. You can read one off any adstransparency.google.com URL.

## `startUrls` (type: `array`):

Paste advertiser or creative permalinks, e.g. https://adstransparency.google.com/advertiser/AR16735076323512287233?region=US

## `region` (type: `string`):

Two-letter country code to restrict the ads to (US, GB, DE, BR, IN ...), or "anywhere" for every country. Regional filtering changes both the result set and the ad counts Google reports.

## `adFormat` (type: `string`):

Keep only one creative format.

## `platform` (type: `string`):

Only ads Google showed on this platform. Google does the narrowing itself, so you only pay for matching ads. It takes one platform per search, so for two platforms run it twice. It does not work with "List advertisers only".

## `maxItems` (type: `integer`):

Stop after this many rows in total, across every target. Only real rows count.

## `listAdvertisersOnly` (type: `boolean`):

With "Advertiser names" filled in, return the matching advertisers (ID, name, verified country, ad-count band) instead of their creatives. Useful when you need to find an advertiser ID first.

## `includeRegionStats` (type: `boolean`):

Fetch each creative's full country breakdown: impression band, first/last shown date and surface split (Search, YouTube, Maps, Shopping, Play) per country. Adds one request per ad.

## `includeAdvertiserDetails` (type: `boolean`):

Look up the advertiser's verified legal name and country once per advertiser.

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

Optional. Leave this empty for a normal run. Supply proxyUrls only if you want your own proxy servers used, and they are used exactly as given.

## `egressMode` (type: `string`):

Advanced. Leave this on Auto. If a run stops with a RATE_LIMITED row, wait a few minutes and run it again.

## Actor input object example

```json
{
  "advertiserDomains": [
    "nike.com",
    "hubspot.com"
  ],
  "advertiserNames": [
    "Nike, Inc."
  ],
  "advertiserIds": [
    "AR16735076323512287233"
  ],
  "region": "US",
  "adFormat": "any",
  "platform": "any",
  "maxItems": 100,
  "listAdvertisersOnly": false,
  "includeRegionStats": false,
  "includeAdvertiserDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "egressMode": "auto"
}
```

# Actor output Schema

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

Creatives in the default dataset: advertiser, format, first and last shown dates, days served, landing domain and preview URL. Only real creative rows are billable; \_sample and \_diagnostic rows are not.

# 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 = {
    "advertiserDomains": [
        "nike.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/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 = { "advertiserDomains": ["nike.com"] }

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/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 '{
  "advertiserDomains": [
    "nike.com"
  ]
}' |
apify call dami_studio/google-ads-transparency-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/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/c9U1R0jHUu6pQwN71/builds/IrtDavoQjM1sNXCJX/openapi.json
