# Google Ads Scraper — Competitor Ads & Change Monitor (`trakk/google-ads-competitor-intelligence`) Actor

Discover Google ads by company, domain, or advertiser ID. Export creatives, copy, dates, impressions, landing pages, emails, phones, and reviews. Monitor NEW, CHANGED, and STOPPED competitor ads.

- **URL**: https://apify.com/trakk/google-ads-competitor-intelligence.md
- **Developed by:** [Kelopr](https://apify.com/trakk) (community)
- **Categories:** Lead generation, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 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/platform/actors/running/actors-in-store#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 Competitor Intelligence & Change Monitor

See which Google ads a competitor is running, inspect the creative details, and monitor what appears, changes, or disappears.

You do not need to know anything about scraping or APIs. Paste a company domain, choose a mode, and click **Start**.

### 🚀 Your first run — click by click

1. Open the Actor page in Apify.
2. Click **Try for free** if you are on the Store page. This opens the **Input** tab.
3. Under **🎯 Workflow**, select **⚡ Quick Scan**.
4. Under **🏢 Companies, domains, or advertiser URLs**, remove the example and enter a real company domain, for example `example-brand.test`.
5. Leave **🌍 Region** set to **Anywhere** for the broadest search.
6. Enter `10` under **💯 Ads per target** for a small first run.
7. Leave the optional enrichment switches off for now.
8. Click **Start**.
9. Wait until the run status becomes **Succeeded**.
10. Open the **Output** tab and choose **Ads overview**.

Each row is one ad. Click **Open ad** to verify it in Google Ads Transparency Center.

If the run succeeds but finds nothing, check the spelling, use the company's domain instead of its name, and set the region to **Anywhere**.

### 🏢 What should I enter?

You can add one or many targets. Enter one target per line.

| What you enter | Example | When to use it |
|---|---|---|
| Domain — recommended | `example-brand.test` | Best option for a normal competitor search |
| Company name | `Example Brand` | Discovery when you do not know the domain or advertiser ID |
| Advertiser ID | `AR12345678901234567` | Exact advertiser identity; avoids similarly named companies |
| Transparency Center URL | `https://adstransparency.google.com/advertiser/AR12345678901234567` | Exact advertiser copied from Google |

A company-name search can return several legal advertiser entities. This is normal. Use a domain, advertiser ID, or advertiser URL when you need one exact identity.

### 🎯 Choose the right workflow

#### ⚡ Quick Scan

Choose this for a fast overview or a large list of competitors.

It returns:

- advertiser name, ID, and domain;
- creative ID;
- ad format: `text`, `image`, or `video`;
- first and last shown timestamps;
- preview image or interactive preview when Google exposes one;
- direct advertiser and ad links;
- coverage status for the search.

Recommended first input:

```json
{
  "workflow": "quick_scan",
  "targets": ["example-brand.test"],
  "region": "anywhere",
  "maxResultsPerTarget": 10,
  "adFormat": "all"
}
```

#### 🔬 Deep Creative

Choose this when you need more than a list of ads. The Actor opens each creative and saves every extra field Google makes available.

It can add:

- headline, description, call to action, and combined creative text;
- landing page and visible URL;
- image, asset, and interactive preview URLs;
- creative variant count;
- global impression range;
- global and selected-region delivery dates;
- region IDs, region count, and delivery-surface codes.

Deep Creative makes extra requests, so it is slower than Quick Scan. Start with 10–25 ads before requesting hundreds.

```json
{
  "workflow": "deep_creative",
  "targets": ["example-brand.test"],
  "region": "US",
  "maxResultsPerTarget": 25
}
```

Some creatives expose only rendered media. Empty headline, landing-page, or impression fields mean Google did not expose that value; the Actor does not invent it.

#### 🔔 Monitor & Compare

Choose this when you want recurring competitor alerts.

##### First monitor run

1. Select **🔔 Monitor & Compare**.
2. Enter the competitors you want to watch.
3. Enter a recognizable **Monitor name**, for example `weekly-competitors`.
4. Set a result limit high enough to collect the complete advertiser result set.
5. Click **Start**.

The first run creates a baseline. Its rows are marked `BASELINE`.

##### Second and later monitor runs

Run the Actor again with the same:

- `monitorName`;
- targets;
- region;
- format and date filters.

The result can contain:

| Status | Meaning |
|---|---|
| `BASELINE` | First saved snapshot |
| `NEW` | Creative was not present in the previous snapshot |
| `CHANGED` | The same creative ID changed; inspect `changedFields` |
| `STOPPED` | Creative disappeared from a complete result set |
| `UNCHANGED` | Creative is still the same; returned only when requested |

The Actor does not claim that an ad stopped when the requested result limit was reached or the source was processed only partially.

##### Schedule the monitor

1. After a successful baseline run, click **Save as a new task**.
2. Give the task a clear name.
3. In the left Apify menu, open **Schedules**.
4. Click **Create new**.
5. Choose how often the check should run.
6. Click **Add → Actor task** and select the task you saved.
7. Enable the schedule.

Keep the task input stable. Changing the monitor name creates a separate history.

### 🎨 Filter by format, date, or region

- **Ad format**: choose all formats, text, image, or video.
- **Region**: choose where the ads were shown. **Anywhere** provides the broadest discovery.
- **Active on or after** (`dateFrom`): keeps ads whose last-shown date reaches this date.
- **Started on or before** (`dateTo`): keeps ads whose first-shown date is not later than this date.
- Dates must use `YYYY-MM-DD`, for example `2026-08-01`.

`dateFrom` cannot be later than `dateTo`. If it is, the run summary tells you exactly what to correct.

### 📇 Add public contacts

Turn on **📇 Public website contacts** to inspect each unique advertiser website.

Possible fields:

- `email` and `emails`;
- `websitePhone` and `websitePhones`;
- `website` and `contactPageUrls`;
- LinkedIn, Instagram, Facebook, YouTube, TikTok, and X/Twitter links when found.

Contacts are extracted only from public pages. A missing email or phone means the inspected website pages did not expose one.

### 📍 Add business details and reviews

Turn on **📍 Business profile** to request a confidence-checked Google Maps match.

For a strong, unambiguous match, the Actor can add:

- business name;
- address and phone;
- official website and Maps URL;
- rating and review count when exposed by the source;
- up to five public review texts and ratings.

To include review text, set **⭐ Review texts per advertiser** from `1` to `5`.

Large brands can have hundreds of stores using the same domain. The Actor rejects a weak or arbitrary location instead of presenting one branch's phone and reviews as information about the whole brand. Check `businessMatchStatus`:

| Status | Meaning |
|---|---|
| `exactDomain` | Domain and business name match confidently |
| `strongName` | Strong business-name match |
| `lowConfidence` | Candidate was found but its data was not attached |
| `ambiguousMultipleLocations` | Several plausible locations exist; no random branch was selected |
| `notFound` | No suitable business candidate was found |

### 📊 Where are my results?

After a run finishes, open **Output**. Four ready-made views are available:

| Output tab | What you see |
|---|---|
| **Ads overview** | Preview, advertiser, format, dates, status, and source link |
| **Creative intelligence** | Copy, assets, landing pages, impression ranges, and regions |
| **Monitor changes** | New, changed, stopped, baseline, and unchanged ads |
| **Contacts & reviews** | Public contacts and confidence-checked business information |

The **Storage → Dataset** page contains the same rows with every available field.

#### Export to CSV, Excel, or JSON

1. Open the run.
2. Open **Output** or **Storage → Dataset**.
3. Click **Export results**.
4. Choose CSV, Excel, JSON, XML, or another available format.
5. Download the file.

### 📦 Important output fields

#### Identity and source

| Field | Meaning |
|---|---|
| `target` | Value you entered |
| `advertiserId` | Google's `AR...` advertiser identifier |
| `advertiserName` | Advertiser name returned by Google |
| `advertiserCountry` | Advertiser country when exposed |
| `domain` | Advertised domain when exposed |
| `creativeId` | Google's `CR...` creative identifier |
| `transparencyUrl` | Direct link to this ad in Google Ads Transparency Center |
| `advertiserUrl` | Direct link to the advertiser page |

#### Ad and delivery

| Field | Meaning |
|---|---|
| `format` | `text`, `image`, `video`, or `unknown` |
| `firstShown` / `lastShown` | First and last source timestamps from the search result |
| `previewImageUrl` | Best preview image when exposed |
| `imageUrls` / `assetUrls` | Media URLs found in the creative |
| `previewUrls` | Interactive creative-preview URLs |
| `globalImpressionsLower` / `globalImpressionsUpper` | Source-provided impression range |
| `globalFirstShown` / `globalLastShown` | Global delivery dates from creative details |
| `regionsCount` / `regionCriteriaIds` | Delivery footprint reported by Google |

#### Data confidence

| Field | Meaning |
|---|---|
| `detailStatus` | Whether creative detail loading completed |
| `coverageStatus` | Whether the requested result set was complete |
| `matchedLowerBound` / `matchedUpperBound` | Google's result estimate when exposed |
| `businessMatchStatus` | Confidence result for optional business enrichment |

### 🧭 Coverage statuses

| Status | Meaning |
|---|---|
| `complete` | Every available result was traversed |
| `limitReached` | More ads exist than the requested maximum |
| `partial` | Some usable ads were saved, but a request failed |
| `noAds` | The target resolved but no matching ads were found |
| `failed` | The target could not be processed |

`matchedLowerBound` and `matchedUpperBound` are source-provided ranges, not guessed exact totals.

### 📦 Fictional example row

The following values are examples only. They do not represent a real company or person.

```json
{
  "recordType": "ad",
  "target": "example-brand.test",
  "workflow": "deep_creative",
  "advertiserId": "AR12345678901234567",
  "advertiserName": "Example Brand Ltd.",
  "domain": "example-brand.test",
  "creativeId": "CR98765432109876543",
  "format": "image",
  "firstShown": "2026-08-01T10:00:00Z",
  "lastShown": "2026-08-18T18:30:00Z",
  "previewImageUrl": "https://cdn.example-brand.test/example-preview.png",
  "globalImpressionsLower": 1000,
  "globalImpressionsUpper": 2000,
  "coverageStatus": "limitReached",
  "changeStatus": "CURRENT",
  "transparencyUrl": "https://adstransparency.google.com/advertiser/AR12345678901234567/creative/CR98765432109876543?region=anywhere"
}
```

### 🔌 Run through the API

Replace `YOUR_APIFY_TOKEN` with your own Apify API token.

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/trakk~google-ads-competitor-intelligence/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow": "quick_scan",
    "targets": ["example-brand.test"],
    "region": "anywhere",
    "maxResultsPerTarget": 10
  }'
```

The run's default Dataset contains the ad rows. The `OUTPUT` record contains a short summary, target coverage, duration, enrichment counts, and monitor counts. `ADVERTISER_SUMMARIES` contains one rollup per advertiser.

### ❓ Troubleshooting

#### The run succeeded but returned zero rows

1. Check the spelling.
2. Use the company's domain instead of its name.
3. Set the region to **Anywhere**.
4. Remove date and format filters.
5. Open Google Ads Transparency Center and confirm that the advertiser currently has visible ads.

#### I entered an invalid value

The Actor finishes safely with `INPUT_NEEDS_ATTENTION` instead of crashing. Open **Output → Input help** to see what is wrong, how to fix it, and a working example Input. Correct the value and run again.

#### The Actor returned fewer ads than expected

Check `coverageStatus`. `limitReached` means you should increase **Ads per target**. A date or format filter can also reduce the result count.

#### Some headline or landing-page fields are empty

Google does not expose identical fields for every creative format. The Actor keeps unavailable values empty instead of guessing them.

#### The preview column is empty for a video

Some ads expose an interactive `previewUrls` entry instead of a static image.

#### I received several advertisers for one company name

The brand may use multiple legal entities. Copy the correct advertiser's `AR...` ID and use that as the next target.

#### I enabled reviews but received none

Review text is attached only when one business is a confident match. A global brand, marketplace, or multi-location chain is intentionally rejected when one exact location cannot be identified safely.

#### What should I use for regular monitoring?

Save a successful Monitor & Compare input as an Apify Task, schedule that task, and keep the monitor name and filters unchanged.

# Actor input Schema

## `workflow` (type: `string`):

Quick Scan finds ads fast. Deep Creative opens every creative for richer fields. Monitor & Compare saves a snapshot and classifies changes on later runs.

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

One target per line. A domain such as example.com is the easiest and most reliable choice. Company names, AR advertiser IDs, and Transparency Center advertiser URLs are also accepted.

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

Where the ads were shown. Anywhere gives the broadest discovery.

## `maxResultsPerTarget` (type: `integer`):

Maximum ads saved for each company or domain.

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

Keep every format, or focus on image, text, or video ads.

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

Optional YYYY-MM-DD date. Keeps ads whose last-seen date reaches this date.

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

Optional YYYY-MM-DD date. Keeps ads first seen by this date.

## `includeCreativeDetails` (type: `boolean`):

Adds creative variants, copy when exposed, asset URLs, impression ranges, regional delivery, and landing-page fields. Always enabled by Deep Creative.

## `enrichContacts` (type: `boolean`):

Visits each unique advertiser website and extracts public emails, phones, contact pages, and social profiles.

## `enrichBusiness` (type: `boolean`):

Adds a phone, address, rating, and review count only when a Google Maps business match is confident and unambiguous.

## `maxReviewsPerAdvertiser` (type: `integer`):

Fetch up to five public Google Maps review texts for a confident single-location match. Set 0 to skip reviews.

## `monitorName` (type: `string`):

Stable name for this competitor set. Used only by Monitor & Compare to keep snapshots separate.

## `includeUnchanged` (type: `boolean`):

Off by default so recurring monitor datasets contain only useful changes.

## `maxContactPages` (type: `integer`):

Homepage plus likely contact/about/support pages inspected for public contacts.

## `maxAdvertisersPerTarget` (type: `integer`):

Maximum advertiser identities followed when a company name, rather than a domain or AR ID, is entered.

## `concurrency` (type: `integer`):

Parallel detail and enrichment requests. The default is tuned for 1 GB runs.

## `geoCriteriaId` (type: `integer`):

Optional advanced override for a country/region/city ID from Google Ads geo target constants.

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

Connection settings for larger or repeated runs.

## Actor input object example

```json
{
  "workflow": "quick_scan",
  "targets": [
    "nike.com"
  ],
  "region": "anywhere",
  "maxResultsPerTarget": 10,
  "adFormat": "all",
  "dateFrom": "",
  "dateTo": "",
  "includeCreativeDetails": false,
  "enrichContacts": false,
  "enrichBusiness": false,
  "maxReviewsPerAdvertiser": 0,
  "monitorName": "default",
  "includeUnchanged": false,
  "maxContactPages": 2,
  "maxAdvertisersPerTarget": 3,
  "concurrency": 16,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `creativeIntelligence` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `contacts` (type: `string`):

No description

## `inputHelp` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

## `advertiserSummaries` (type: `string`):

No description

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

// Run the Actor and wait for it to finish
const run = await client.actor("trakk/google-ads-competitor-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 = {
    "workflow": "quick_scan",
    "targets": ["nike.com"],
    "maxResultsPerTarget": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("trakk/google-ads-competitor-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 '{
  "workflow": "quick_scan",
  "targets": [
    "nike.com"
  ],
  "maxResultsPerTarget": 10
}' |
apify call trakk/google-ads-competitor-intelligence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,trakk/google-ads-competitor-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/bdEpDDq5fh4Dyx1sk/builds/GSrTjPaSzJRN0uwaG/openapi.json
