# LinkedIn Ad Library Change Monitor (`monkey.d.scraping/linkedin-ad-library-change-monitor`) Actor

Track competitor LinkedIn ads and emit only deterministic changes.

- **URL**: https://apify.com/monkey.d.scraping/linkedin-ad-library-change-monitor.md
- **Developed by:** [Monkey D. Scraping](https://apify.com/monkey.d.scraping) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 ad trackeds

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/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

## LinkedIn Ad Library Change Monitor

Monitor competitor LinkedIn ads and get a clean change feed from the public LinkedIn Ad Library. Each scheduled run compares the current result set with the previous snapshot and returns only what changed: new ads, disappeared ads, and advertisers never seen before.

This is a deterministic LinkedIn advertising monitor for competitive intelligence, campaign tracking, lead-generation research, and daily or weekly alerts. It uses no login, cookies, AI, or external Actor.

### At a glance

| Capability | Details |
|---|---|
| Data source | Public LinkedIn Ad Library, logged out |
| Search targets | Advertiser, payer, keyword, or direct Ad Library URL |
| Input | One company or a list of monitored inputs |
| State | Previous snapshot in the Actor key-value store |
| Change feed | New ads, disappeared ads, and new advertisers |
| Reference data | Complete current snapshot per monitor |
| Scheduling | Designed for daily or weekly runs |
| Authentication | None required |
| AI enrichment | None; deterministic normalization and set comparison |

### What this Actor does

- Tracks one company or a list of competitors in one run.
- Searches by advertiser, payer, keyword, or a direct LinkedIn Ad Library URL.
- Detects new LinkedIn ads and ads that disappeared since the previous complete run.
- Flags a new advertiser appearing in the monitored results.
- Preserves a full current snapshot for audit and historical comparison.
- Calculates active-ad count, ads first seen in the period, average observed longevity, format mix, and payer-to-advertiser mapping.
- Keeps state isolated by `monitorId`, so separate competitors, users, and schedules do not share baselines.

### Search phrases this Actor answers

- track competitor LinkedIn ads
- monitor LinkedIn Ad Library
- get alerts on new LinkedIn ads
- detect when competitor ads disappear
- see which companies advertise on LinkedIn
- track LinkedIn advertiser and payer activity
- compare competitor ad campaigns over time
- export LinkedIn ad change events to a dataset

### Why the change feed is useful

Most ad-library scrapers return a flat dump that must be compared manually. This Actor does the set comparison for you. The first run creates a baseline and intentionally emits no `new` alerts. Later complete runs emit only differences, so the `changes` dataset is suitable for schedules, downstream automations, and daily review.

Results are conservative: if LinkedIn truncates the page at `maxResults`, returns a challenge/block page, or produces an unparseable empty response, the previous snapshot is not replaced and false disappearance alerts are avoided.

#### Event semantics

| Situation | Output |
|---|---|
| First run for a new `monitorId` and scope | Baseline only; no change alerts |
| Complete run with an ad not in the previous snapshot | `new` |
| Complete run with a previous ad no longer present | `disappeared` |
| Advertiser never seen in this monitor's history | `new-advertiser` |
| Result set truncated at `maxResults` | Change alerts are suppressed |
| LinkedIn challenge, block, or parser failure | Previous snapshot is preserved |

### This Actor vs similar LinkedIn Actors

| Capability | **This Actor** | [SolidCode LinkedIn Ads Scraper](https://apify.com/solidcode/linkedin-ads-scraper) | [Jaybird LinkedIn Ad Library Scraper](https://apify.com/jaybird/linkedin-ad-library-scraper) |
|---|---|---|---|
| Primary job | Monitor changes between scheduled runs | Extract LinkedIn ads in bulk | Extract LinkedIn ads and optional details |
| Output | Change events **plus** full snapshot | Flat ad rows | Flat ad rows with basic/enriched modes |
| Stateful baseline | Yes, isolated by `monitorId` | Not the core workflow | Not the core workflow |
| Alerts | New, disappeared, new advertiser | Consumer compares results separately | Consumer compares results separately |
| Search | Advertiser, payer, keyword, direct URL | Keyword, advertiser, direct URL | Company, payer, keyword, direct URL |
| Public/no login | Yes | Yes | Yes |
| Indicative pricing | `$0.50 / 1,000` tracked ads + change events | `$0.50 / 1,000` basic; `$0.90 / 1,000` enriched | `$0.35 / 1,000` basic; `$1.50 / 1,000` enriched |

The positioning is intentionally different: those Actors are optimized for extracting ad data, while this Actor is optimized for recurring monitoring and a ready-to-use change feed. Competitor prices are observed Store prices and can change.

### Other Actors from the same publisher

Use these complementary Actors for a broader monitoring workflow:

| Actor | Best for | Main output |
|---|---|---|
| [Telegram Keyword Search & Channel Scraper](https://apify.com/monkey.d.scraping/telegram-keyword-search-channel-scraper) | Public Telegram research and keyword discovery | Matching posts and channel data |
| [Google Shopping Price Tracker & Seller Monitor](https://apify.com/monkey.d.scraping/google-shopping-price-change-seller-monitor) | Product prices, offers, and seller monitoring | Changed offers and product snapshot |

### Output datasets

The default dataset contains a run manifest with links to two monitor-specific datasets:

- **LinkedIn Ad Change Events & Metrics** (`changes`): event rows for `new`, `disappeared`, and `new-advertiser`, plus per-company aggregate metrics.
- **LinkedIn Ad Library Current Snapshot** (`snapshot`): every normalized ad observed in the latest complete result set.

Each normalized ad has a stable ID derived from the LinkedIn Ad Library detail URL. Snapshot state is stored in the Actor key-value store and updated only after both output datasets are written successfully.

### Input example

```json
{
  "monitorId": "acme-competitors-weekly",
  "advertisers": ["OpenAI", "Anthropic"],
  "country": "IT",
  "dateRange": "30d",
  "searchType": "advertiser",
  "maxResults": 100
}
```

Use the same `monitorId` and filter scope on recurring runs. Changing the scope intentionally starts a new baseline instead of creating false changes.

### Indicative launch pricing

The planned pay-per-event structure stays close to low-cost LinkedIn ad scrapers while charging a small premium for change detection:

| Event | Indicative price |
|---|---:|
| `actor-start` | `$0.00005` per run |
| `ad-tracked` | `$0.0005` per normalized ad (`$0.50 / 1,000`) |
| `change-detected` | `$0.003` per emitted change |

These prices are indicative until PPE charging is enabled and confirmed in the Apify Store. Dataset summary and snapshot rows should not create additional billable events.

### Reliability and limitations

The source is LinkedIn's public Ad Library, so its availability, pagination, markup, and fields can change. No login or private LinkedIn data is accessed. Run a weekly smoke test and verify that both named datasets receive records before relying on alerts in production.

Billing event names are defined in the Actor code as `actor-start`, `ad-tracked` (one per normalized ad), and `change-detected` (one per emitted change). Store pricing can be configured separately after publication.

# Actor input Schema

## `monitorId` (type: `string`):

A unique namespace for this monitor, for example acme-competitors-weekly. Use a different value for each user or independent monitor.

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

Company names, LinkedIn advertiser names, payer names, keywords, or direct LinkedIn Ad Library URLs to monitor.

## `country` (type: `string`):

Optional ISO country code filter.

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

Optional Ad Library date range, for example 30d or 2026-01-01..2026-08-10.

## `searchType` (type: `string`):

Choose whether the query targets an advertiser, payer, or keyword.

## `maxResults` (type: `integer`):

Maximum number of ads to normalize for each monitored input.

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

Optional Apify Proxy configuration for the public LinkedIn request.

## Actor input object example

```json
{
  "monitorId": "linkedin-ad-library-daily-smoke-test",
  "advertisers": [
    "OpenAI"
  ],
  "country": "IT",
  "dateRange": "30d",
  "searchType": "advertiser",
  "maxResults": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `overview` (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 = {
    "monitorId": "linkedin-ad-library-daily-smoke-test",
    "advertisers": [
        "OpenAI"
    ],
    "country": "IT",
    "dateRange": "30d",
    "searchType": "advertiser",
    "maxResults": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("monkey.d.scraping/linkedin-ad-library-change-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 = {
    "monitorId": "linkedin-ad-library-daily-smoke-test",
    "advertisers": ["OpenAI"],
    "country": "IT",
    "dateRange": "30d",
    "searchType": "advertiser",
    "maxResults": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("monkey.d.scraping/linkedin-ad-library-change-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 '{
  "monitorId": "linkedin-ad-library-daily-smoke-test",
  "advertisers": [
    "OpenAI"
  ],
  "country": "IT",
  "dateRange": "30d",
  "searchType": "advertiser",
  "maxResults": 5
}' |
apify call monkey.d.scraping/linkedin-ad-library-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,monkey.d.scraping/linkedin-ad-library-change-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/OwkGBiWDfwfR48DWP/builds/N8bylRLVW4Ht2BYbT/openapi.json
