# Google Ads Transparency Scraper — From $0.40/1K (`luminar/google-ads-transparency-intelligence`) Actor

Scrape Google Ads Transparency Center creatives, advertisers and dates. Track competitor Google ads and detect new, updated and safely ended ads.

- **URL**: https://apify.com/luminar/google-ads-transparency-intelligence.md
- **Developed by:** [Luka](https://apify.com/luminar) (community)
- **Categories:** Marketing, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.34 / 1,000 baseline 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Google Ads Transparency Center Scraper & Tracker

**Scrape Google Ads Transparency Center creatives and advertiser data — then detect new, updated and safely ended competitor ads on later runs.**

Point it at a brand, a domain, an advertiser ID or a Transparency Center URL. Get back the advertiser, the creatives, the dates and the copy that Google exposes, straight from the [Google Ads Transparency Center](https://adstransparency.google.com). Run the same query again later and you get only what actually moved.

No Google Ads account and no Ads API key required.

***

### 🎯 What can this Actor do?

🔎 **Search by brand, domain, advertiser ID or Transparency URL** — mix as many targets as you like in one run

⚡ **Fast by architecture, strict by design** — the measured cloud run delivered 500 unique ads in under one minute end to end, with zero browser requests, blocks, retries or duplicates

🖼️ **Get the creatives** — direct image and media URLs, without paying to download the files

📝 **Get the ad copy where Google exposes it** — headlines and descriptions, on the formats that carry them

🔗 **See the destination candidate** — the outbound URL observed on the ad, reported honestly as unverified

🌍 **Filter before you scrape** — region and ad format, so you pay only for the ads you want

🔔 **Track changes over time** — later runs deliver only `NEW`, `UPDATED` and safely proven `ENDED`, never unchanged filler

✅ **Know when your data is complete** — every target reports whether the source was exhausted, capped or only partially read

***

### 🆚 Baseline or Changes — which one do I need?

This is the only real decision you have to make. Everything else has a sensible default.

| | **BASELINE** | **CHANGES** |
|---|---|---|
| What you get | Every ad running right now | Only what moved since your last run |
| Answers | *"What is my competitor advertising?"* | *"What did my competitor change?"* |
| Best for | Creative research, audits, swipe files | Scheduled monitoring, alerts, weekly reports |
| Needs a previous run | No | Second run onwards |
| A run with no changes | — | Succeeds with an empty dataset, costs you nothing per result |
| Price | $0.40 / 1,000 results | $0.80 / 1,000 changes |

Start with `BASELINE`. Switch to `CHANGES` when you want the Actor to do the comparing for you.

***

### 📊 What you actually get — measured, before you pay

For standard commercial ads, Google Ads Transparency Center publishes advertiser, creative and delivery-transparency data — not private campaign performance metrics. This Actor returns what Google actually makes public and never pads your export with guessed metrics or decorative empty columns.

Real coverage from a 500-row Nike domain run on 2026-08-20:

| Field group | Rows | Coverage |
|---|---:|---:|
| Creative ID, advertiser, format, dates, display domain, source URL | 500/500 | **100%** |
| Direct image / media URL | 331/500 | **66%** |
| Sanitized preview URL | 169/500 | 34% |
| Structured headline & description copy | 70/500 | **14%** |
| Observed destination candidate | 61/500 | 12% |

**Structured ad copy is format-dependent at the source.** In this measured sample, Google exposed machine-readable headline or description fields on 14% of rows. When text exists only inside a rendered image or video, it is not available as source-verified structured copy; OCR can only approximate what is visually present. This Actor prioritizes source truth over guessed text. If you need consistently structured copy, use the Meta companion Actor below.

Google does not publish a normalized CTA, direct video asset or verified final landing-page field across every commercial-ad format. Some creative formats expose more than others, but these values do not have a universal, stable source contract. This Actor therefore exposes only verified source fields and omits unavailable values instead of pretending they were extracted. `landingPageCandidateUrl`, where present, is an **observed and unverified** candidate — not a confirmed advertiser landing page.

***

### ⬇️ Input

The simplest possible run:

```json
{
  "searchTargets": ["nike.com"]
}
```

A monitored competitor set:

```json
{
  "productLevel": "CHANGES",
  "searchTargets": ["nike.com", "adidas.com", "AR16735076323512287233"],
  "region": "US",
  "maxAdsPerTarget": 200
}
```

Image ads only, one market:

```json
{
  "searchTargets": ["Nike"],
  "region": "DE",
  "adFormat": "IMAGE",
  "maxAdsPerTarget": 500
}
```

`searchTargets` accepts brand names, domains, `AR…` advertiser IDs, and official `adstransparency.google.com` URLs pasted straight from your browser.

***

### ⬆️ Output

One row per ad. Real rows from the measured run, not idealized examples.

A typical row — identity plus a directly exposed image:

```json
{
  "creativeId": "CR04739221842466701313",
  "advertiserId": "AR16735076323512287233",
  "advertiserName": "Nike, Inc.",
  "displayDomain": "nike.com",
  "format": "TEXT",
  "firstShownAt": "2023-11-16T22:05:24.809Z",
  "lastShownAt": "2026-08-20T20:52:01.813Z",
  "imageUrls": ["https://tpc.googlesyndication.com/archive/simgad/14068473521641712518"],
  "primaryMediaUrl": "https://tpc.googlesyndication.com/archive/simgad/14068473521641712518",
  "region": "ANYWHERE",
  "searchTarget": "nike.com",
  "coverageStatus": "CAPPED",
  "sourceAdUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR04739221842466701313"
}
```

A less common row where Google also exposed copy and a destination candidate:

```json
{
  "creativeId": "CR02992220324038180865",
  "advertiserName": "Nike Retail BV",
  "format": "IMAGE",
  "headlines": ["Nike Oficjalny"],
  "descriptions": ["Męskie spodenki piłkarskie Dri-FIT Nike Academy - Czerń/czerń/biel - Rozmiar: L"],
  "landingPageCandidateUrl": "https://shopping.producthero.com/?utm_source=google&utm_medium=css",
  "coverageStatus": "CAPPED",
  "sourceAdUrl": "https://adstransparency.google.com/advertiser/AR18378488041124659201/creative/CR02992220324038180865"
}
```

Export as JSON, CSV, Excel, XML or RSS, or pull it straight from the Apify API.

#### Built-in dataset views

- **`changes`** — the monitoring view: only actionable detected changes.
- **`creativeResearch`** — a visual swipe-file view with creative, copy, dates, domain and source evidence.
- **`allData`** — every buyer-facing field, without internal diagnostics.

#### What is in every row

| Group | Fields |
|---|---|
| **Ad identity** | `creativeId`, `format`, `versionId` |
| **Advertiser** | `advertiserId`, `advertiserName`, `displayDomain` |
| **Copy** | `headlines`, `descriptions` |
| **Creatives** | `imageUrls`, `primaryMediaUrl`, `previewUrl` |
| **Destination** | `landingPageCandidateUrl` |
| **Delivery** | `firstShownAt`, `lastShownAt`, `region` |
| **Change tracking** | `changeStatus`, `changedFields` |
| **Run context** | `searchTarget`, `coverageStatus`, `observedAt`, `sourceAdUrl` |

Optional fields that Google did not expose are **omitted from the row** rather than delivered as empty columns.

***

### 💰 How much does it cost?

| Event | Price |
|---|---|
| Run start | $0.01 |
| Baseline result | $0.40 / 1,000 |
| Detected change | $0.80 / 1,000 |

Real examples:

| What you run | You pay |
|---|---|
| 100 ads from one brand | ~$0.05 |
| 1,000 ads across several brands | ~$0.41 |
| A monitoring run where nothing changed | **$0.01** |

You are billed for the events above — not for compute, proxy traffic or storage. Copy and media are included whenever Google exposes them; there is no enrichment surcharge.

***

### ⚡ Optimized for exceptional speed and clean data

The extraction engine uses a direct HTTP/RPC route instead of launching a browser for every creative. That keeps large snapshots fast, inexpensive and deterministic without sacrificing validation or duplicate protection.

Every figure below comes from a real private cloud run, read back from the Apify API after it finished.

| | |
|---|---|
| Rows delivered | 500 unique, zero duplicates |
| Route | 100% HTTP/RPC, zero browser requests |
| Blocks, challenges, retries | 0 |
| Application data work | **3.6 seconds for 500 rows** |
| Complete Apify run | **55.4 seconds**, including container startup |

That is 500 validated, deduplicated Google ad rows in under one minute end to end, without browser-per-creative overhead. HTTP/RPC is the primary route. A residential browser starts only when the direct route cannot deliver, and the run reports when that happened.

***

### ✅ How do I know the data is complete?

Most scrapers hand you rows and let you guess whether that was everything. This one tells you, per target:

| Status | Meaning |
|---|---|
| `COMPLETE` | The source ran out of ads. You have all of them. |
| `CAPPED` | Your result limit was reached first. More ads exist. |
| `PARTIAL` | Rows are valid, but neither the cap nor the end was reached. |
| `EMPTY` | Proven zero matching ads — not a silent failure. |

This matters most for change tracking. **An incomplete run can never produce an `ENDED` event** — otherwise a capped window would look like your competitor switching off campaigns. `CAPPED`, `PARTIAL`, failed and mismatched scopes never raise a false ending.

The trade-off is deliberate: this Actor would rather tell you an ad is still running than wrongly tell you it stopped.

***

### ⚡ Ready-made workflows

Three public Task Examples are available:

1. **[Monitor Google ads daily](https://apify.com/luminar/google-ads-transparency-intelligence/examples/monitor-google-ads-daily)** — bounded daily change monitoring.
2. **[Weekly Google ad change report](https://apify.com/luminar/google-ads-transparency-intelligence/examples/weekly-google-ad-change-report)** — a scheduled detected-change report.
3. **[Build a Google ad swipe file](https://apify.com/luminar/google-ads-transparency-intelligence/examples/build-google-ad-swipe-file)** — collect current creatives for research.

**Need Facebook and Instagram too?** Use the companion [Facebook Ad Library Scraper & Change Tracker](https://apify.com/luminar/meta-ads-library-creative-changefeed) — same output philosophy and the same change-tracking guarantees.

A free n8n → Telegram workflow is prepared for release. It uses the official Apify node to run this paid Actor, wait for completion, turn change rows into a readable alert, and send it through Telegram. The old Slack-only JSON under `integrations/n8n/` is a historical draft and must not be used.

### 🤖 For AI agents / MCP

This public, limited-permission Actor can be discovered and run through the hosted [Apify MCP server](https://docs.apify.com/integrations/mcp). Use it when an agent needs current Google competitor-ad creatives, source-backed transparency data, or a scheduled changefeed.

Example prompts:

- `Find the current Google ads for nike.com and return the creative evidence.`
- `Monitor these Google advertisers and report only new, updated, or safely ended ads.`
- `Build a Google Ads Transparency creative research dataset for these domains.`

Connect the standard Apify MCP server; no Actor-specific MCP server is required.

***

### ❓ FAQ

**What can this Actor *not* tell me?**
For standard commercial ads, Google Ads Transparency Center does not publish conversions, CPA or ROAS, bids, keywords, campaign-level spend or proof that an ad performed well. These are not hidden fields that a different scraper can unlock. Political ads and certain regional disclosures may include additional impression, reach or targeting information, but those limited exceptions are not universal commercial-ad fields and are not promised by this Actor.

**Why does only 14% of rows have ad text?**
The 14% figure is measured coverage from this 500-ad sample, not a universal Google ceiling. Google publishes machine-readable copy only for formats that expose it as structured data. When copy exists solely inside a rendered image or video, no scraper can recover it as source-verified structured copy; OCR is a best-effort visual interpretation, not the original field. This limitation is measured and published instead of hidden.

**Why are CTA and direct video URLs not guaranteed?**
Google does not expose normalized CTA and direct video-asset fields across every commercial-ad format. Some creatives expose additional assets; others expose only a rendered preview. Because no universal source contract exists, these fields are not promised as standard output; missing values are omitted rather than fabricated or inferred.

**Is the landing URL the real advertiser page?**
Not necessarily. Google Ads Transparency Center does not provide a universal verified final-destination field and is not designed for landing-page click-through verification. `landingPageCandidateUrl` is the destination observed on the creative and is labelled as an unverified candidate. Shopping and CSS intermediaries frequently appear there. Visiting an advertiser's website or enriching its domain is not proof of the final destination for that specific ad, so this Actor does not present it as one.

**Do I need a Google Ads account?**
No. The Transparency Center is public and this Actor needs no account, no API key and no credentials from you.

**Can I run this on a schedule?**
Yes. Set `productLevel` to `CHANGES` and each run delivers only what moved. A run where nothing changed costs just the start fee.

**Will the ad order be stable between runs?**
Not necessarily. Google can reorder results, which is exactly why change detection compares material content rather than position, and why a capped window is never treated as a complete history.

***

### 🔐 How your run is handled

- Live source traffic runs only inside Apify Cloud through a residential proxy. Local execution fails closed and uses fixtures.
- Credentials, cookies, proxy URLs, signed payloads, fingerprints and internal query IDs never appear in your rows.
- Media binaries are not downloaded — their URLs are already in the source data.
- Limited Actor permissions are sufficient; the Actor asks for nothing more.

***

### 💬 Feedback

Missing a field, a target type that fails, or a filter you need? Open an issue on the Actor's Issues tab. Bug reports with the run ID get fixed fastest.

# Actor input Schema

## `productLevel` (type: `string`):

<b>Baseline</b> returns the ads running right now. <b>Changes</b> returns only what actually moved since your previous run of the same query — new, updated, or safely proven ended. A run with nothing new succeeds with an empty dataset and costs you nothing per result.

## `searchTargets` (type: `array`):

One target per line — a brand name, a domain like <code>nike.com</code>, an <code>AR…</code> advertiser ID, or a Google Ads Transparency Center URL pasted straight from your browser.

## `maxAdsPerTarget` (type: `integer`):

Upper limit of ads collected for each target. You are billed per delivered result, so start small: 15 for a cheap test, 100 for normal research.

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

Where the ad was shown. Pick <i>Anywhere</i> for the broadest view.

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

Keep every format, or return only text, image or video ads.

## `maxProxyGb` (type: `number`):

Hard stop for the whole run. The run ends cleanly and reports what it delivered rather than overspending.

## `timeoutSeconds` (type: `integer`):

Maximum wall-clock run time.

## `maxDeliveryEvents` (type: `integer`):

Billing guard across all targets combined, on top of the per-target limit.

## `maxRetriesPerOperation` (type: `integer`):

How many times to retry a transient source failure before giving up on that step.

## Actor input object example

```json
{
  "productLevel": "BASELINE",
  "searchTargets": [
    "nike.com"
  ],
  "maxAdsPerTarget": 15,
  "region": "ANYWHERE",
  "adFormat": "ALL",
  "maxProxyGb": 0.05,
  "timeoutSeconds": 900,
  "maxDeliveryEvents": 10000,
  "maxRetriesPerOperation": 2
}
```

# Actor output Schema

## `dataset` (type: `string`):

Open the strict buyer dataset in detected changes, creative research, or all buyer fields view.

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

// Run the Actor and wait for it to finish
const run = await client.actor("luminar/google-ads-transparency-intelligence").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 = {
    "searchTargets": ["nike.com"],
    "maxAdsPerTarget": 15,
}

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

```

## MCP server setup

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

```

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/NfRO0e6GXztBNtaFO/builds/35ZSmy80VaKoxb44V/openapi.json
