# Google Ads Spy: Competitor Ads by Domain (+ Meta) (`watershowdigital/competitor-ad-spy`) Actor

See every ad a competitor runs on Google Search, YouTube and Display by domain or advertiser: ad text, videos, landing pages, countries and impressions. Optional Meta Ad Library via your API token.

- **URL**: https://apify.com/watershowdigital/competitor-ad-spy.md
- **Developed by:** [WaterShow Digital](https://apify.com/watershowdigital) (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 detailed 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 Spy: Competitor Ads by Domain (+ Meta)

See **every ad your competitor runs on Google** (Search, YouTube, Display) just by entering their website. For each ad you get the headline, description, call to action, landing page, YouTube video, the countries where it ran, impressions and how long it has been running. Add your own Meta token and the same run also pulls their **Facebook and Instagram ads** from the official Meta Ad Library API.

Data comes from the public [Google Ads Transparency Center](https://adstransparency.google.com/) and the official [Meta Ad Library API](https://www.facebook.com/ads/library/api/). No login, no browser extension.

### What you can do with it

- 🔎 **Spy on competitors.** Enter `hubspot.com` and see every Google ad that sends people to HubSpot: copy, offers, videos, landing pages.
- 🎬 **Collect YouTube ad videos.** Video ads come with the YouTube link, thumbnail, duration and channel.
- 🌍 **See where they advertise.** Countries for each ad, with impressions where Google publishes them (EU countries).
- ⏱️ **Find their winners.** Ads running for months are usually the ones that make money. Sort by `daysShown` or `firstShown`.
- 🧪 **Get ideas for your own ads.** Headlines, descriptions and calls to action of the best ads in your niche in one table.
- 📈 **Monitor new ads.** Schedule the run daily with "Only running ads" and get notified about new campaigns.

### Input

| Field | Example | What it does |
|---|---|---|
| Competitor domains | `notion.com`, `https://www.hubspot.com` | All Google ads leading to this site |
| Advertisers | `Canva`, `AR13309761427309854721`, a Transparency Center link | All ads of a verified advertiser (a name is matched to the best advertiser) |
| Country | `US`, `GB`, `DE` | Only ads shown in this country (empty = all countries) |
| Ad format | text / image / video | Only Search, Display or YouTube ads |
| Only running ads | on | Skip ads not shown in the last 3 days |
| Max ads per domain or advertiser | `50` | Limit per source |
| Ad text, videos, countries and impressions | on | Open each ad for its full details (off = faster list with preview images) |
| Meta access token | `EAAB…` | Optional. Adds Meta (Facebook, Instagram) ads |

#### Example input

```json
{
  "domains": ["notion.com", "hubspot.com"],
  "region": "US",
  "format": "video",
  "maxAdsPerSource": 100
}
```

### Output

One row per ad. Example (Google, video):

```json
{
  "platform": "google",
  "advertiserName": "Notion Labs, Inc",
  "adUrl": "https://adstransparency.google.com/advertiser/AR13309761427309854721/creative/CR02184150513950392321",
  "format": "video",
  "isActive": true,
  "firstShown": "2026-06-18T06:44:54.000Z",
  "lastShown": "2026-10-24T00:16:17.000Z",
  "daysShown": 129,
  "headline": "Work faster together with Notion",
  "longHeadline": "Stop switching tools. Build docs, tasks, and wikis in Notion fast.",
  "description": "Plan, collaborate, and build faster together with Notion",
  "callToAction": "Learn more",
  "displayUrl": "notion.com",
  "destinationUrl": "https://www.notion.com/lp/ent?nid=ddvmq9t",
  "youtubeUrl": "https://www.youtube.com/watch?v=ihR5nRHFyMk",
  "videoDuration": "0:18",
  "impressionsMin": 4000,
  "impressionsMax": 5000,
  "countries": ["FR", "LU", "BE"],
  "regions": [{ "countryCode": "FR", "impressionsMin": 3000, "impressionsMax": 4000, "firstShown": "2026-06-17", "lastShown": "2026-10-23" }]
}
```

Meta rows have `bodyText`, `headline`, `description`, `displayUrl`, `publisherPlatforms`, `languages`, `euTotalReach`, targeting and a link to the ad in the Meta Ad Library.

A short summary per source (advertiser found, ads collected, Google's estimate of the advertiser's total ads) is saved as `SUMMARY` in the key-value store.

### Good to know

- **Text (Search) ads** are published by Google as an image of the ad, so for them you get `imageUrl` instead of separate headline and description fields. Video and many Display ads come with the full text.
- **Impressions** are published by Google only for ads shown in the EU. Elsewhere you get the countries and dates.
- **Google limits fast requests.** The Actor runs at a steady pace and continues from another IP after a pause, so large runs take a few minutes. Keep the default Apify Proxy on.
- **Meta:** the Ad Library website blocks automated access, so this Actor uses only the official API with your own token. Meta returns all ads delivered in the **EU** and political or social issue ads elsewhere. To get a token: create an app at [developers.facebook.com](https://developers.facebook.com/), confirm your identity at [facebook.com/ID](https://www.facebook.com/ID), then generate a user access token in the Graph API Explorer. The token is stored as a secret input and never written to the results or logs.

### Pricing

You pay only for ads you get:

| Event | Price |
|---|---|
| Google ad with full details (text, video, countries, impressions) | $1.50 per 1,000 |
| Google ad, list only (details off) | $0.80 per 1,000 |
| Meta ad | $0.80 per 1,000 |

No monthly fee. Example: 500 competitor ads with full details cost $0.75.

### FAQ

**Is it legal?** The Actor reads public ad transparency data that Google and Meta publish so anyone can see who advertises what. Use it in line with the terms of these services.

**Why did I get fewer ads than the advertiser has?** Check the country and format filters and the max ads limit. The `SUMMARY` record shows Google's estimate of the advertiser's total ads.

**A name matched the wrong advertiser.** Use the advertiser ID (AR…) or paste the link from the Transparency Center.

**Can I get notified about new ads?** Yes: schedule the Actor with "Only running ads" and connect an integration (Slack, email, webhook) in Apify.

Questions or a feature request? Open an issue on the Actor page.

# Actor input Schema

## `domains` (type: `array`):

Websites whose ads you want to see, e.g. notion.com or https://www.hubspot.com. You get every Google ad that sends people to this domain.

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

Advertiser names as shown in Google Ads Transparency (e.g. "HubSpot, Inc."), advertiser IDs (AR…) or Transparency Center links. For a name the best matching verified advertiser is used.

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

Only ads shown in this country: two-letter code like US, GB, DE. Leave empty for ads from all countries.

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

Only text (Search), image (Display) or video (YouTube) ads.

## `onlyActive` (type: `boolean`):

Skip ads that have not been shown in the last 3 days.

## `maxAdsPerSource` (type: `integer`):

Stop after this many ads for each domain, advertiser or Meta search.

## `includeDetails` (type: `boolean`):

Open each Google ad for its headline, description, landing page, YouTube video, countries and impressions. Turn off for a faster, cheaper list of ads with preview images only.

## `platforms` (type: `array`):

Where to look for ads. Meta needs your own access token below.

## `metaAccessToken` (type: `string`):

Your token for the official Meta Ad Library API (create an app at developers.facebook.com, confirm your identity at facebook.com/ID, then generate a user token). Meta returns all ads delivered in the EU and political ads elsewhere. Without a token only Google is searched.

## `metaCountries` (type: `array`):

Countries where the ads were delivered (two-letter codes). Meta shows all ads only for EU countries. Default: DE, FR, IT, ES, NL.

## `metaSearchTerms` (type: `array`):

Keywords to search in Meta ads. By default the brand from each domain (notion.com → notion) and the advertiser names are used.

## `metaPageIds` (type: `array`):

Exact Facebook page IDs of the advertisers (more precise than search terms).

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

Google limits fast requests from one IP. Apify Proxy lets the run continue from another IP after a pause.

## Actor input object example

```json
{
  "domains": [
    "notion.com"
  ],
  "format": "all",
  "onlyActive": false,
  "maxAdsPerSource": 50,
  "includeDetails": true,
  "platforms": [
    "google",
    "meta"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All collected ads with text, media, landing pages, dates, countries and impressions.

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

Per-source summary: advertiser found, ads collected and Google's estimate of the advertiser's total ads.

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

// Run the Actor and wait for it to finish
const run = await client.actor("watershowdigital/competitor-ad-spy").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 = {
    "domains": ["notion.com"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("watershowdigital/competitor-ad-spy").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 '{
  "domains": [
    "notion.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call watershowdigital/competitor-ad-spy --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,watershowdigital/competitor-ad-spy"
        }
    }
}
```

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/cTqgYN92bWyNVYCf2/builds/IPHwR8alhgimXV6fk/openapi.json
