# Competitor Ads Monitor — Google & LinkedIn Ad Library (`latentlark/competitor-ads-monitor`) Actor

Track competitor ads from Google Ads Transparency Center and LinkedIn Ad Library. Enter domains, get ad copy, creatives, landing pages, dates, regions and impressions. Schedule with 'only new ads' for alerts.

- **URL**: https://apify.com/latentlark/competitor-ads-monitor.md
- **Developed by:** [LatentLark](https://apify.com/latentlark) (community)
- **Categories:** Marketing, SEO tools, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 google 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

## Competitor Ads Monitor — Google & LinkedIn Ad Library

See which ads your competitors are running. Give it domains or company names and it pulls every ad from the **Google Ads Transparency Center** (Search, Display, YouTube) and the **LinkedIn Ad Library**. Each ad comes back as one clean row: copy, creative, landing page, first and last shown dates, regions and impressions.

Schedule it with **Only new ads** and you get a short list of each competitor's new ads every day or week, ready for Slack, email, Sheets or your BI tool.

![Competitor Ads Monitor results: one row per ad with advertiser, platform, format, headline, CTA, landing page, first and last shown dates and regions](https://api.apify.com/v2/key-value-stores/Tv899H9p8Kim9T8M2/records/competitor-ads-results-table.png?signature=1PQWNlKIlSaEV18k8J7q7)

*Real output from a test run for `hubspot.com` (Google and LinkedIn). Built and maintained by LatentLark.*

### Quick start (first run in about 30 seconds)

1. Click **Try for free** (or **Start** in Console). The form is prefilled with `hubspot.com`, Google only, and 5 ads.
2. Click **Start**. You get 5 HubSpot ads in the **Output** tab for about $0.015.
3. Replace `hubspot.com` with your competitors' domains (one per line). Raise **Max ads per advertiser** when you want more.
4. For LinkedIn, add **LinkedIn Ad Library** under **Platforms** and add the company names in **LinkedIn companies** (e.g. `HubSpot`).
5. For alerts, turn on **Only new ads since last run**, give it a **Monitor key** like `crm-competitors`, **Save as task** and add a daily **Schedule**.

**How the first run looks** (fill the form, click Start, get results):

![Walkthrough: the prefilled form, click Start, then the ads table in the Output tab](https://api.apify.com/v2/key-value-stores/Tv899H9p8Kim9T8M2/records/competitor-ads-walkthrough.gif?signature=nxEXyS7Vzazld6aC6jVW)

### What you can do with it

- **Competitive intel:** see the messaging, offers and landing pages a rival is testing right now.
- **New-ad alerts:** schedule a daily run with `onlyNew` and get only the ads launched since the last run.
- **Creative research:** collect headlines, CTAs, images and videos from a whole category for swipe files.
- **Agency reporting:** monitor client competitors by region and date range.
- **Market mapping:** find out who advertises on a domain, including partners and agencies.

### Input

| Field | What it does |
|---|---|
| `domains` | Google: competitor domains (`hubspot.com`), advertiser IDs (`AR…`), Transparency Center URLs or advertiser names |
| `linkedinCompanies` | LinkedIn: company name, `linkedin.com/company/...` URL or numeric company ID |
| `platforms` | `google`, `linkedin` or both |
| `maxAdsPerAdvertiser` | Newest ads first; caps cost on big advertisers (0 = no limit) |
| `regions` | Country codes like `US`, `DE`, `GB` (empty = all) |
| `dateRange` | Any time, the last 7, 30, 90 or 365 days, or a custom range |
| `domainOwnerOnly` | Google: keep only the advertiser that owns the domain and drop agencies or resellers that link to it (on by default) |
| `includeDetails` | Adds ad copy, landing page, video, regions and impressions (one extra lookup per ad) |
| `onlyNew` + `monitorKey` | Output only ads not seen in earlier runs with the same key |

Example (Google, US, last 30 days, alerts):

```json
{ "domains": ["hubspot.com", "salesforce.com"], "platforms": ["google"], "regions": ["US"], "dateRange": "last30days", "maxAdsPerAdvertiser": 50, "onlyNew": true, "monitorKey": "crm-competitors" }
```

Example (Google + LinkedIn):

```json
{ "domains": ["hubspot.com"], "linkedinCompanies": ["HubSpot"], "platforms": ["google", "linkedin"], "maxAdsPerAdvertiser": 20 }
```

### Output

One dataset item per ad:

```json
{
  "platform": "google",
  "advertiserName": "HubSpot",
  "advertiserId": "AR13611357312189988865",
  "domain": "hubspot.com",
  "adId": "CR15298995467690442753",
  "format": "text",
  "headline": "HubSpot Customer Platform",
  "bodyText": "See how HubSpot's AI-powered customer platform helps you grow better.",
  "cta": null,
  "landingUrl": "https://www.hubspot.com/",
  "imageUrls": [],
  "videoUrl": null,
  "firstShown": "2023-03-01T00:00:00Z",
  "lastShown": "2026-10-24T00:00:00Z",
  "regions": ["NL", "DE"],
  "impressionsRange": { "min": 30000, "max": 35000 },
  "isNew": true,
  "stoppedRunning": false,
  "adLibraryUrl": "https://adstransparency.google.com/advertiser/AR…/creative/CR…?region=anywhere",
  "scrapedAt": "2026-10-24T21:00:00Z"
}
```

Rows also include `daysShown`, `regionStats` (Google: first and last shown plus impressions per country; LinkedIn: impression share per country), `paidBy` and `targeting` (LinkedIn: language, location and targeting parameters), `thumbnailUrl` and `sourceInput`. A per-input `SUMMARY` record is written to the run's key-value store.

### How monitoring works

The first run with a `monitorKey` stores every ad it finds as the baseline. Each later run with `onlyNew: true` outputs, and charges for, only ads that were not seen before. `stoppedRunning` is `true` when an ad hasn't been shown for `stoppedAfterDays` days (3 by default).

### Pricing

Pay per event, no subscription: a small start fee per run plus each ad saved to the dataset.

| Event | Price |
|---|---|
| Actor start (per run, at the default 256 MB memory) | $0.005 |
| Google ad saved | $0.002 ($2 per 1,000 ads) |
| LinkedIn ad saved | $0.004 ($4 per 1,000 ads) |

Example: a daily `onlyNew` check on 5 competitors that finds 20 new Google ads costs about $0.045 per run. Residential proxy for LinkedIn is included. Set a **maximum cost per run** in Apify and the Actor stops cleanly when it reaches it. Ads skipped by `onlyNew` are not charged.

### Limitations

- **Google text ads:** Google often keeps older text ads only as an image snapshot. For those, `headline` and `bodyText` are empty and the creative is in `imageUrls`. Newer responsive search ads and YouTube ads include full copy.
- Google doesn't publish impressions for every region. EU countries usually have them, the US often does not.
- **LinkedIn (beta):** LinkedIn blocks cloud server IPs, so LinkedIn requests use Apify residential proxy (included in the price, about 15 KB of traffic per ad). It is slower than Google: expect a few seconds per ad. LinkedIn shows impressions as ranges and per-country shares only, and the Ad Library covers roughly the last 12 months.
- The domain-owner filter matches advertiser names to the domain. Turn `domainOwnerOnly` off to see every advertiser.
- This Actor reads public, official ad-transparency libraries only. It does not log in or collect personal data.

### FAQ

**Can I get alerts in Slack or email?** Yes. Schedule the Actor with `onlyNew` and connect an Apify integration (Slack, email, Zapier, Make or a webhook).
**Can I export to Google Sheets?** Yes. Use Apify's Google Sheets integration or [LatentLark's Google Sheets Export & Import](https://apify.com/latentlark/sheets-export) (no OAuth, so scheduled writes keep working).
**Why are headline and text empty for some Google ads?** Google keeps many older text ads only as an image snapshot. The creative is in `imageUrls`. See Limitations.
**I got 0 ads for a domain. Why?** The advertiser may not run Google ads in the selected regions or dates, or its advertiser name doesn't match the domain. Turn off `domainOwnerOnly`, clear `regions`, or paste the advertiser's Ads Transparency Center URL or `AR…` ID. The `SUMMARY` record shows what was found for each input.
**Found a problem?** Open an issue on the Actor's Issues tab.

### More from LatentLark

- [Career Page Jobs API](https://apify.com/latentlark/ats-career-jobs): every open job from Workday, Personio, Greenhouse, Lever, Ashby and 3 more ATS as clean JSON, with only-new-jobs monitoring.
- [Google Sheets Export & Import (No OAuth)](https://apify.com/latentlark/sheets-export): send any Actor's results to a Google Sheet on a schedule without Google login or expiring tokens.
- [Telegram Channel Monitor](https://apify.com/latentlark/telegram-channel-monitor): scrape and monitor public Telegram channels (posts, views, reactions) with no login, only-new mode and webhooks.
- [Google Maps Leads Website Audit & Pitch Generator](https://apify.com/latentlark/local-lead-audit): audit local business websites from Google Maps leads (SSL, speed, tracking, booking), find owner contacts and get a one-line cold-email pitch.

# Actor input Schema

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

One per line. A competitor website (hubspot.com), a Google advertiser ID (AR10072600183532683265), an Ads Transparency advertiser URL, or an advertiser name (Salesforce). Used for Google.

## `linkedinCompanies` (type: `array`):

One per line. Company name as the advertiser appears on LinkedIn (HubSpot), a LinkedIn company URL (linkedin.com/company/hubspot) or a numeric company ID. Used when LinkedIn is selected.

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

Which ad libraries to check. LinkedIn is in beta.

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

Newest ads first. Keeps cost predictable on big advertisers. 0 = no limit.

## `regions` (type: `array`):

2-letter country codes, e.g. US, DE, GB. Empty = all regions.

## `dateRange` (type: `string`):

Only ads shown in this period. For 'Custom', set start and end date.

## `startDate` (type: `string`):

YYYY-MM-DD. Used when 'Ads shown in' is Custom.

## `endDate` (type: `string`):

YYYY-MM-DD. Used when 'Ads shown in' is Custom.

## `domainOwnerOnly` (type: `boolean`):

Google also lists ads from other advertisers (agencies, resellers) that link to the domain. On = keep only advertisers whose name matches the domain (fallback: the biggest advertiser). Off = all advertisers.

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

One extra lookup per ad for headline, text, CTA, landing URL, video, regions and impression ranges. Turn off for a faster creative list.

## `onlyNew` (type: `boolean`):

Output only ads not seen in previous runs with the same monitor key. The first run saves everything as the baseline. Ideal for scheduled alerts.

## `monitorKey` (type: `string`):

Name for this watchlist's memory (e.g. 'crm-competitors'). Use different keys for different schedules.

## `stoppedAfterDays` (type: `integer`):

stoppedRunning = true when an ad was last shown more than this many days ago.

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

LinkedIn blocks cloud server IPs, so LinkedIn requests go through Apify residential proxy (very little traffic: about 15 KB per ad). Google never uses the proxy.

## `debugSaveHtml` (type: `boolean`):

Save raw LinkedIn pages to the key-value store for troubleshooting.

## Actor input object example

```json
{
  "domains": [
    "hubspot.com"
  ],
  "platforms": [
    "google"
  ],
  "maxAdsPerAdvertiser": 5,
  "dateRange": "anytime",
  "domainOwnerOnly": true,
  "includeDetails": true,
  "onlyNew": false,
  "monitorKey": "default",
  "stoppedAfterDays": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "debugSaveHtml": false
}
```

# Actor output Schema

## `overview` (type: `string`):

Ads found in this run: advertiser, format, copy, landing page, first/last shown, regions, impressions, library link.

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

Per-input counts, matched advertisers and errors.

# 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": [
        "hubspot.com"
    ],
    "platforms": [
        "google"
    ],
    "maxAdsPerAdvertiser": 5,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("latentlark/competitor-ads-monitor").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": ["hubspot.com"],
    "platforms": ["google"],
    "maxAdsPerAdvertiser": 5,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("latentlark/competitor-ads-monitor").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": [
    "hubspot.com"
  ],
  "platforms": [
    "google"
  ],
  "maxAdsPerAdvertiser": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call latentlark/competitor-ads-monitor --silent --output-dataset

```

## MCP server setup

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

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/LkdHNutf9XUvd3Hnr/builds/FCMqVDTPGaFvVqR8N/openapi.json
