# Google Ads Transparency Scraper with Ad Text (`wheaten_steelpan/google-ads-transparency-scraper`) Actor

Collects the ads any company runs on Google from the Ads Transparency Center, including the headline, description, display URL and sitelinks of text ads as plain text. You can also check a list of domains to see which ones advertise on Google, how many ads they run and since when.

- **URL**: https://apify.com/wheaten\_steelpan/google-ads-transparency-scraper.md
- **Developed by:** [Vanja V](https://apify.com/wheaten_steelpan) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 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 with Ad Text

This actor collects the ads that any company runs on Google, using Google's public Ads Transparency Center. You give it a list of domains or advertisers, and for each ad you get the format, the dates it was shown and a link to the ad itself. For text ads you also get the headline, description, display URL and sitelinks as plain text, so you can read and compare the copy in a spreadsheet instead of clicking through ad images one by one.

If you only need to know whether a list of companies advertises on Google, there's a domain check mode as well. It tells you, for each domain, whether it's running ads, roughly how many, and how long it has been advertising.

Ads cost $1.50 per 1,000, and reading the text of text ads adds $1.00 per 1,000. You only pay for results: there's no fee for starting a run, and you aren't charged for targets that fail.

![Output rows: advertiser and region, headline, description, display URL, sitelinks and last shown date for seven text ads](https://api.apify.com/v2/key-value-stores/q8PJZbCwHQk7l8xQe/records/output-example.png)

*Seven text ads from real runs in the US, Germany, France, Japan and Brazil, with the text exactly as the actor returns it.*

### What people use it for

Most people use it to research competitors. You can see every ad a company runs across Google Search, YouTube and display, and because the text of their search ads comes back as plain text, it's easy to sort and compare their messaging or to collect headline ideas from a whole market.

The domain check is useful for building lead lists and for agencies looking for prospects. You can paste in hundreds of domains and quickly see which of them are advertising on Google right now and which don't show any ads.

You can also use the date filters to see what an advertiser was running in a particular month. An ad whose `lastShown` date is today or yesterday is still running.

### Example

Here's an input that asks for the text ads of three advertisers in the US, given in three different ways:

```json
{
    "targets": ["buffer.com", "Nike, Inc.", "AR13568824525935607809"],
    "region": "US",
    "format": "text",
    "maxAdsPerTarget": 200
}
```

Each ad comes back as one row like this:

```json
{
    "target": "buffer.com",
    "advertiserId": "AR03915127329008910337",
    "advertiserName": "Buffer Inc",
    "creativeId": "CR10235424077351223297",
    "format": "text",
    "firstShown": "2024-08-27T07:04:54.000Z",
    "lastShown": "2026-09-29T14:38:46.000Z",
    "targetDomain": "buffer.com",
    "region": "US",
    "adUrl": "https://adstransparency.google.com/advertiser/AR03915127329008910337/creative/CR10235424077351223297?region=US",
    "imageUrl": "https://tpc.googlesyndication.com/archive/simgad/15536267169289402687",
    "previewUrl": null,
    "textStatus": "read",
    "headline": "Buffer",
    "description": "Buffer has everything you need to grow an engaged audience including a powerful free plan.",
    "displayUrl": "www.buffer.com/",
    "sitelinks": [
        { "title": "Get Started For $0", "description": "" },
        { "title": "Sign Up For Free Today", "description": "" }
    ],
    "error": null
}
```

### What you get

In the default *Ads* mode you get one row per ad. Each row has the advertiser's name and ID, the ad's ID and format (text, image or video), the first and last dates Google showed it, the website it points to, and links to the ad's page on the Transparency Center and to the ad's image or preview.

For text ads, the actor also reads the ad itself. Google stores most text ads as images, so an AI model reads the visible text from the image. It only returns what's actually visible, and leaves out anything the image cuts off rather than guessing at it. Some text ads have no image, only Google's own preview of the ad, and for those the actor takes the text straight from the preview. The `textStatus` field tells you which of these happened for each row.

In *Domain check* mode you get one row per domain instead. It says whether the domain advertises, gives Google's count of its ads, lists the advertisers behind those ads, and shows the earliest and latest dates they were shown. The check needs just one request per domain, so it's fast: 29 domains took two seconds in our test.

At the end of each run, the `SUMMARY` record and the status message tell you how every target went. Each one is marked `ok`, `no-ads`, `blocked` or `invalid-input`, and next to the number of ads returned you'll see Google's own count for that target, so you can tell how complete the result is. If a target returns nothing, you'll get a row explaining why, so a run never quietly finishes with an empty dataset.

Rows are saved as they come in. If a run times out or you stop it, you keep everything it found up to that point.

### Input

| Field | What it does |
|---|---|
| Targets | One per line. This can be a domain (`nike.com`), a website link, an advertiser ID (`AR…`), an advertiser's exact name as Google lists it (`Nike, Inc.`), or a Transparency Center link for an advertiser or domain. |
| What to get | *Ads* for one row per ad, or *Domain check* for one row per domain. |
| Region | The country where the ads were shown. By default the actor looks everywhere. |
| Ad format | All formats, or only text, image or video ads. |
| Shown from / until | Limits the results to ads that ran between these dates (YYYY-MM-DD). |
| Max ads per target | Stops after this many ads for each target. The default is 100. |
| Read ad text | Reads the text of text ads, which is charged per text ad. It's on by default. |

If you give an advertiser name that doesn't exactly match a name Google uses, you'll get an error row listing the closest names Google knows, and you can copy the right one from there.

### Pricing

| Event | Price |
|---|---|
| Ad returned | $0.0015 ($1.50 per 1,000) |
| Text ad read (headline, description, display URL, sitelinks) | $0.001 ($1.00 per 1,000) |
| Domain checked | $0.002 ($2.00 per 1,000) |

Here's what some typical runs would cost:

| You get | Cost |
|---|---|
| 1,000 image or video ads | $1.50 |
| 1,000 text ads with their text | $2.50 |
| 1,000 text ads with *Read ad text* turned off | $1.50 |
| 1,000 domains checked | $2.00 |

Apify's platform usage is already included in these prices, and there's no charge for starting a run. You also don't pay for targets that are blocked or invalid, or for ad searches that find no ads. If the actor can't read the text of a text ad, you pay for the ad but not for the text. In domain check mode every domain that gets checked counts, including the ones that turn out not to advertise, since that's an answer too.

If you want to limit what a run can cost, set a maximum cost when you start it (`maxTotalChargeUsd` in the API). The actor will stop once the next ad would go over that amount, and the summary will say that it stopped because of the limit.

### Use it through the API

This call runs the actor and returns the rows when it's done:

```bash
curl -X POST "https://api.apify.com/v2/acts/wheaten_steelpan~google-ads-transparency-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"targets": ["buffer.com"], "region": "US", "format": "text", "maxAdsPerTarget": 50}'
```

It waits up to 5 minutes. For bigger runs, the Apify clients will start the run and wait for it to finish for you.

JavaScript (`npm install apify-client`):

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('wheaten_steelpan/google-ads-transparency-scraper').call({
    targets: ['buffer.com', 'linear.app'],
    region: 'US',
    format: 'text',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

Python (`pip install apify-client`):

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("wheaten_steelpan/google-ads-transparency-scraper").call(run_input={
    "targets": ["hubspot.com", "notion.so", "canva.com"],
    "mode": "domain-check",
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["domain"], row["advertises"], row["adCountMin"], row["adCountMax"])
```

### Use it from an AI agent (MCP)

You can give an AI assistant such as Claude Desktop, Cursor or VS Code access to this actor through Apify's MCP server:

```json
{
  "mcpServers": {
    "google-ads-transparency": {
      "url": "https://mcp.apify.com?tools=wheaten_steelpan/google-ads-transparency-scraper"
    }
  }
}
```

Clients that support OAuth will ask you to sign in to Apify the first time. For other clients, add your token in a header: `"headers": { "Authorization": "Bearer <APIFY_TOKEN>" }`. The assistant then has a tool that takes domains or advertisers and returns their ads.

### Speed and limits

Google returns ads in pages of 40, and reading the text of text ads is what takes most of the time, at about five ads a second. In our tests, a run of 300 ads, 282 of them text ads, finished in 49 seconds.

Big advertisers can have thousands of ads, so *Max ads per target* is there to keep runs short. The summary shows Google's total next to what was fetched, so you'll know if there's more. For large advertisers Google gives that total as a range, such as 7,000 to 8,000, and for small ones it gives an exact number.

There's no filter by platform (Search, YouTube, Maps, Play or Shopping) yet, and you can't give the actor a link to a single ad. Both are on the list if people ask for them.

### Good to know

When you search by domain, you get every ad Google associates with that domain, and that can include other advertisers. A search for hubspot.com, for example, also returns ads from businesses whose landing pages are hosted on HubSpot. The `advertiserName` field lets you tell them apart.

Some advertisers use keyword insertion, writing headlines like `{KeyWord:Nike Tech}` that Google fills in with whatever the person searched for. The Transparency Center shows these as written, and the actor returns them the same way.

Responsive and dynamic search ads put together different headlines for different searches. The actor returns the version Google shows in its ad list, and the ad's own page on the Transparency Center may show other versions.

The data comes from Google's public Ads Transparency Center, and this actor isn't affiliated with Google. If something doesn't work or you'd like another field, open an issue in the Issues tab and I'll take a look.

# Actor input Schema

## `targets` (type: `array`):

One per line: a domain (nike.com), a website link, an advertiser ID (AR…), an advertiser's exact name as Google lists it ("Nike, Inc."), or an Ads Transparency Center link for an advertiser or domain. Duplicates are fetched once.

## `mode` (type: `string`):

Ads: every ad for each target, one row per ad. Domain check: one row per domain saying whether it advertises on Google, Google's ad count, the advertisers and the dates, from a single request per domain. Domain check takes domains and website links only.

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

Only ads shown in this country. "Anywhere" covers every region. A Transparency Center link that names its own region keeps it.

## `format` (type: `string`):

Only ads of this format.

## `dateFrom` (type: `string`):

Only ads shown on or after this date (YYYY-MM-DD).

## `dateTo` (type: `string`):

Only ads shown on or before this date (YYYY-MM-DD).

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

Stop after this many ads for each target. Large advertisers run thousands of ads; the run summary shows Google's own count next to what was fetched.

## `readAdText` (type: `boolean`):

Read the headline, description, display URL and sitelinks of text ads, from their images or from Google's ad preview when there is no image; charged per text ad read. Turn off to get the ads alone.

## Actor input object example

```json
{
  "targets": [
    "nike.com"
  ],
  "mode": "ads",
  "region": "anywhere",
  "format": "all",
  "maxAdsPerTarget": 100,
  "readAdText": true
}
```

# Actor output Schema

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

One row per ad: advertiser, format, first and last shown, image or preview link, and for text ads the headline, description, display URL and sitelinks. In domain-check mode, one row per domain. Targets that returned nothing because of a problem get one error row each. Download as CSV, JSON or Excel from the Export button.

## `summary` (type: `string`):

What happened to each target: ok, no ads, blocked, invalid, failed or not run, with the ads fetched next to Google's own ad-count range.

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

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

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

```

## MCP server setup

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