# Google Ads Transparency Scraper: SpyFu Alternative, No Login (`nebulacolors/google-ads-transparency`) Actor

Google Ads Transparency Center scraper and Google ad library export: every ad a competitor runs on Search, YouTube and Display, by name, website or advertiser ID. Format, first and last shown dates, preview, ad link and, optionally, the countries it ran in. No login. $1 per 1,000 ads.

- **URL**: https://apify.com/nebulacolors/google-ads-transparency.md
- **Developed by:** [Nebula Colors LLC](https://apify.com/nebulacolors) (community)
- **Categories:** Marketing, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 ads

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 Scraper: SpyFu Alternative, No Login

A pay-per-result alternative to SpyFu-style competitor ad research, straight from the Google Ads Transparency Center, Google's own public ad library: $1 per 1,000 ads, no login, no subscription.

### Google Ads Transparency scraper use cases

- See every ad a competitor runs on Google Search, YouTube and Display right now, and since when.
- Catch the day a brand starts or stops a campaign.
- Collect a competitor's YouTube and image ads for creative research.
- See which countries an advertiser targets.

### What you get for each Google ad

Get the ads a competitor runs on Google Search, YouTube and Display, up to all of them, straight from the Google Ads Transparency Center, Google's public ad library. Type a company name, a website or an advertiser ID. For each ad you get the format, the first and last day it was shown, a preview, the link to the ad on Google's site and, if you want, the countries it ran in. It's a Google ads scraper with no login and no API key, at $1 per 1,000 ads. It stops at 100 ads per advertiser unless you raise that. It works for people and for AI agents through Apify's MCP server.

### Input

| Field | What to put |
|---|---|
| Advertisers | One per line. A name (`Nike, Inc.`), a website (`nike.com`) or an advertiser ID (`AR16735076323512287233`). |
| Country | A two-letter code like `US` or `GB` to list only ads shown there, or `anywhere`. |
| Ad format | All, text, image or video. |
| Max ads per advertiser | Where to stop for each line. Big brands have thousands. Default 100. |
| Add the countries each ad ran in | Off by default. Looks up each ad's own page for its countries. |
| Proxy | Apify Proxy, on by default. |

How each line is read:

- **Advertiser ID** (starts with `AR`): that advertiser's ads.
- **Website**: the ads that point to that site, from every account that runs them. Big brands often advertise from more than one account. For nike.com that includes Nike, Inc. and Nike Retail BV. The advertiser row for a website lists every account found, with how many of the returned ads each ran. A site that hosts other people's pages, like notion.so, also brings back ads from anyone who links there.
- **Name**: the Transparency Center's own search. The Actor picks the advertiser whose name matches exactly, with the most ads, and lists up to 5 other matches so you can pick one by ID next time. If no name matches exactly, it takes the Transparency Center's first suggestion, which can be a different company, and the advertiser row says `"exactMatch": false`. Check `advertiserName` there, or use an advertiser ID.

Example:

```json
{
  "advertisers": ["nike.com", "Adidas AG", "AR16735076323512287233"],
  "region": "US",
  "adFormat": "all",
  "maxAdsPerAdvertiser": 200,
  "includeRegionDetails": false
}
```

### Output

The rows below came out of this Actor's own code, run on Google pages saved on October 14, 2026.

One row per ad. Here are two ads for `nike.com` with country details on, from two different Nike accounts:

```json
{
  "query": "nike.com",
  "type": "ad",
  "advertiserId": "AR16735076323512287233",
  "advertiserName": "Nike, Inc.",
  "adId": "CR01365936386246443009",
  "format": "text",
  "targetDomain": "nike.com",
  "firstShown": "2023-11-17T01:35:07.000Z",
  "lastShown": "2026-10-14T17:13:42.000Z",
  "previewImageUrl": "https://tpc.googlesyndication.com/archive/simgad/18315675656631725550",
  "previewScriptUrl": null,
  "adUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR01365936386246443009",
  "regions": [{ "code": "US", "name": "United States", "lastShown": "2026-09-01" }]
}
```

```json
{
  "query": "nike.com",
  "type": "ad",
  "advertiserId": "AR18378488041124659201",
  "advertiserName": "Nike Retail BV",
  "adId": "CR07168715242145316865",
  "format": "image",
  "targetDomain": "nike.com",
  "firstShown": "2021-10-25T07:00:00.000Z",
  "lastShown": "2026-10-14T17:04:33.000Z",
  "previewImageUrl": null,
  "previewScriptUrl": "https://displayads-formats.googleusercontent.com/ads/preview/content.js?client=ads-integrity-transparency&obfuscatedCustomerId=6919916581&creativeId=453317343041&...",
  "adUrl": "https://adstransparency.google.com/advertiser/AR18378488041124659201/creative/CR07168715242145316865",
  "regions": [{ "code": "GB", "name": "United Kingdom", "lastShown": "2026-10-14" }]
}
```

And a YouTube video ad, by advertiser ID, with country details off:

```json
{
  "query": "AR16735076323512287233",
  "type": "ad",
  "advertiserId": "AR16735076323512287233",
  "advertiserName": "Nike, Inc.",
  "adId": "CR10652972250883424257",
  "format": "video",
  "targetDomain": null,
  "firstShown": "2026-07-07T14:04:49.000Z",
  "lastShown": "2026-10-14T14:27:21.000Z",
  "previewImageUrl": null,
  "previewScriptUrl": "https://displayads-formats.googleusercontent.com/ads/preview/content.js?client=ads-integrity-transparency&obfuscatedCustomerId=1287649103&creativeId=807123584309&...",
  "adUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR10652972250883424257"
}
```

- `previewImageUrl` is a picture of the ad. Google shows text ads as pictures too.
- Video and some image ads have no picture. They have `previewScriptUrl`, the script Google uses to draw the ad, and you can watch or view the ad itself on its `adUrl` page.
- `regions` is only there when you turn on country details.
- With a country set, `adUrl` ends in `?region=` and that code.
- An ad's `lastShown` and each country's `lastShown` come from different Google records and can disagree, as in the first sample. Both are Google's own.
- If one ad's country lookup fails, its `regions` is `null`, the row has a `detailsError`, and that ad isn't charged for country details.
- Ad dates are in UTC. A country's `lastShown` is a plain date.

Then one row per advertiser line. This one is for the name `Nike, Inc.` in the US:

```json
{
  "type": "advertiser",
  "query": "Nike, Inc.",
  "matchedBy": "name",
  "advertiserId": "AR16735076323512287233",
  "advertiserName": "Nike, Inc.",
  "exactMatch": true,
  "adCountRange": { "min": 7000, "max": 8000 },
  "adsReturned": 100,
  "error": null,
  "failed": false,
  "alternatives": [
    { "id": "AR06641858037806006273", "name": "Nike", "country": "KE", "adCount": 1 },
    { "id": "AR17365672681860497409", "name": "NIKE SRL", "country": "IT", "adCount": 8 }
  ]
}
```

`adCountRange` is Google's own estimate of how many ads match. It gives a range, not an exact number. `alternatives` lists up to 5 other advertisers with a similar name (2 shown here). The same list is saved as the `ADVERTISERS` record in the run's key-value store.

When a line brings back no ads, `error` says why. With `"failed": false` it means Google has no ads for it with your filters. With `"failed": true` the lookup itself broke, for example because Google blocked the request, and running it again may work.

### Price

- $1.00 per 1,000 ads.
- Country details: $1.00 per 1,000 ads more, only if you turn them on.
- The advertiser rows are free.

### Good to know

- Google limits how fast anyone can read this site, and it blocks an IP that asks too fast. The Actor waits at least 1.5 seconds between requests. That means at least 15 seconds per 1,000 ads, plus about 1.5 seconds per ad for country details. If Google still asks for a captcha, the Actor retries on a fresh proxy IP. With the proxy turned off, it stops with a clear message instead of retrying.
- A worked example: all 8,000 or so Nike ads take about 2 minutes and cost about $8. With country details, add about 3.3 hours and $8 more, because each ad needs its own lookup.
- You can set a maximum charge for a run. The Actor stops when it's reached and keeps what it already saved.
- Text ads are only available as pictures, so their words are not in the data.
- The dates and counts are Google's own.
- This Actor isn't made by Google or connected to it. It reads the same public pages anyone can open.

### Use it from an AI agent

The Actor works through Apify's MCP server like any Store Actor. An agent can find it, read its input and call it. Only `advertisers` is required. A run of a few hundred ads finishes within the MCP call's wait. Runs with country details or thousands of ads take longer, so the agent reads the rows afterwards with `get-dataset-items`, using the dataset ID the call returns.

### FAQ

**How do I see a competitor's Google ads?** Type their company name, website or advertiser ID. You get every ad Google's public ad library lists for them, on Search, YouTube and Display.

**Can I see YouTube ads too?** Yes. YouTube ads come back with their format, first and last day shown, and a preview link.

**Can I see which countries an ad ran in?** Turn on "Add the countries each ad ran in". It's off by default because it reads each ad's own page.

**Do I need a Google account or API key?** No. It reads Google's public ad library with no login.

### More tools from us

- [AI Brand Mention Checker](https://apify.com/nebulacolors/ai-visibility): is your brand named by ChatGPT and Gemini, and who comes first.
- [Website to Markdown Crawler](https://apify.com/nebulacolors/website-content-markdown): a whole site as clean Markdown for LLMs and RAG.
- [Website Screenshot](https://apify.com/nebulacolors/website-screenshot): full page or mobile screenshots of any URL, PNG or JPEG.
- [News & Blog Article Extractor](https://apify.com/nebulacolors/article-extractor): the newest articles from a site or RSS feed, as Markdown.
- [Image Downloader](https://apify.com/nebulacolors/image-downloader): every image on a page, full size, in one ZIP.

### Questions or problems

Open an issue on this Actor's Issues tab. I read them.

# Actor input Schema

## `advertisers` (type: `array`):

One per item: an advertiser name (Nike, Inc.), a website (nike.com) or an advertiser ID (AR16735076323512287233). A website returns the ads of every advertiser that points to it.

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

Two-letter country code, like US or GB, to list only ads shown there. anywhere for all countries.

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

Return only text, image or video ads. All returns every format.

## `maxAdsPerAdvertiser` (type: `integer`):

Stop after this many ads for each advertiser line. Big brands have thousands. Each ad is one charged event.

## `includeRegionDetails` (type: `boolean`):

Adds the countries each ad ran in, with the last day it showed in each. One extra request and one extra charged event per ad.

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

Apify Proxy is on by default. Google blocks an IP that sends too many requests, and the proxy lets the Actor switch to a fresh one.

## Actor input object example

```json
{
  "advertisers": [
    "nike.com"
  ],
  "region": "anywhere",
  "adFormat": "all",
  "maxAdsPerAdvertiser": 100,
  "includeRegionDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `ads` (type: `string`):

All rows as JSON. Rows with type 'ad' hold each ad's advertiser, format, website, first and last shown dates, preview and page link. Rows with type 'advertiser' summarize each input line.

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

Only the advertiser summaries: which advertiser each input line matched, Google's ad count range, how many ads came back and any problem.

# 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 = {
    "advertisers": [
        "nike.com"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nebulacolors/google-ads-transparency").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 = {
    "advertisers": ["nike.com"],
    "proxyConfiguration": { "useApifyProxy": True },
}

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

```

## MCP server setup

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

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/Xz3Y5ueoVD7dtp5Ml/builds/NeCqlGpIP0ENaHikh/openapi.json
