# LinkedIn Ad Library Scraper & Intelligence API (`interactapps/linkedin-ad-library-scraper`) Actor

Scrape LinkedIn's public Ad Library by company ID or keyword. Clean, consistent JSON with free enrichment: CTA type, creative format, language and duplicate detection. Monitor mode returns only new ads — and charges only for those. Built for marketers, agencies and AI agents.

- **URL**: https://apify.com/interactapps/linkedin-ad-library-scraper.md
- **Developed by:** [Nina Mackie](https://apify.com/interactapps) (community)
- **Categories:** Social media, Agents, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 ad delivereds

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 Scraper & Intelligence API

Extract every ad a company is running from LinkedIn's public Ad Library — as clean, consistent JSON your scripts, spreadsheets and AI agents can use immediately. Built for marketers, agencies and developers who need competitor ad intelligence, not raw HTML.

*Every field below was verified against live output on 27 July 2026. We list only what the actor actually returns.*

### Five-minute quick start

1. Click **Try for free**.
2. The default input is pre-filled — just press **Start**.
3. Within a minute you'll have real ads in the dataset tab, exportable as JSON, CSV or Excel.

No configuration, no login, no LinkedIn account required.

#### Get better results: search by company ID

You can search by keyword, but a keyword matches any ad *mentioning* that word — including your competitors' ads. To pull one specific advertiser's ads precisely, use their LinkedIn company ID:

1. Open the company's LinkedIn page and click **Ads**, or visit their Ad Library page.
2. The URL contains `companyIds=` followed by a number. That's the ID.
3. Put that number in `queries`, for example `["1441"]` for Google.

You can mix them: `["1441", "2382910", "crm software"]` works in a single run.

### Presets

| Preset | What it does |
| --- | --- |
| Competitor monitoring | Daily-schedule ready; returns only new or changed ads per run, and charges only for those |
| Creative inspiration | Latest ads matching your keywords |
| Agency pitch research | Full ad history for a target advertiser before a pitch |
| Brand monitoring | Watch for ads mentioning your brand |
| Monthly ad archive | Full snapshot for records or compliance |

### Output

One record per ad. Every documented field is always present — null when unavailable — so your parser never has to guess. Example record (field names exact, values illustrative):

```json
{
  "ad_id": "1475105064",
  "advertiser_name": "Google",
  "promoter_name": null,
  "headline": "Study smarter with Google Gemini",
  "ad_copy": "Level up your exam prep with Google Gemini...",
  "creative_format": "image",
  "image_urls": ["https://media.licdn.com/..."],
  "video_urls": [],
  "detail_url": "https://www.linkedin.com/ad-library/detail/1475105064",
  "cta_type": "learn_more",
  "language": "en",
  "ad_copy_length": 148,
  "is_personal_profile_ad": false,
  "is_duplicate_creative": false,
  "country_filter": "GB",
  "query": "1441",
  "ai_analysis": null,
  "_source": "https://www.linkedin.com/ad-library/search?companyIds=1441",
  "_scraped_at": "2026-07-27T15:04:45.680Z",
  "_first_seen": "2026-07-27T15:04:45.680Z",
  "_last_seen": "2026-07-27T15:04:45.792Z",
  "_record_hash": "446415c7716f..."
}
```

#### Fields worth knowing about

- **is\_personal\_profile\_ad / promoter\_name** — LinkedIn lets companies promote posts from an individual's profile, an executive for instance. Most scrapers report the person as the advertiser, which quietly corrupts competitor analysis. We resolve the paying company into `advertiser_name` and keep the individual in `promoter_name`.
- **ad\_copy\_length** — useful for spotting whether a competitor is testing short-form or long-form copy.
- **is\_duplicate\_creative** — flags the same creative reappearing across runs, so you can tell a genuinely new campaign from a re-serve.
- **\_first\_seen / \_last\_seen** — how long a creative has been live, accumulated across your runs. Long-running creatives are usually the ones performing.

Enrichment (`creative_format`, `cta_type`, `language`, `ad_copy_length`, duplicate detection, first/last seen) is included at no extra charge. Optional **AI campaign analysis** is a separately charged add-on, off by default.

### Use it from anywhere

**Python**

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("InteractApps/linkedin-ad-library-scraper").call(
    run_input={"queries": ["1441"], "country": "GB", "maxResults": 100})
for ad in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(ad["advertiser_name"], ad["headline"])
```

**JavaScript**

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const { defaultDatasetId } = await client
    .actor('InteractApps/linkedin-ad-library-scraper')
    .call({ queries: ['1441'], preset: 'competitor_monitoring' });
const { items } = await client.dataset(defaultDatasetId).listItems();
```

**Claude / GPT agent prompt**

```
Run the linkedin-ad-library-scraper actor with
queries=["<company ID>"] and preset="competitor_monitoring".
Summarise new campaigns: objectives, hooks, CTA types, and how
messaging has changed since the previous run.
```

### Monitor mode (recommended)

Select the **Competitor monitoring** preset, or set `onlyNew: true`, and schedule the actor daily.

The actor remembers every ad it has delivered to you and returns only new or changed ones. **You are charged only for what is returned** — on a day when a competitor launches nothing, the run costs you nothing. The first run backfills their current ads; after that, most days are a handful of records or zero.

This is the cheapest way to never miss a competitor launch, and it is the main reason to leave this actor running rather than pulling data ad hoc.

### Honest limitations

- Data comes from LinkedIn's public Ad Library. Fields LinkedIn does not publish — exact spend, full targeting detail, precise impressions — are not invented by us. What the library exposes varies by region; EU ads show more under DSA rules.
- Keyword search matches ad text, so it returns any advertiser using that phrase. Use company IDs when you want one specific advertiser.
- If LinkedIn changes its page markup, the actor detects it, saves a diagnostic sample and skips rather than emitting malformed records. We aim to ship repairs within 24 to 48 hours. Runs that return nothing are not charged.
- Public, non-personal data only. No login-walled content, and no personal data of private individuals.

### Pricing and support

$0.004 per delivered ad, plus optional AI analysis per record.

You are charged only for ads actually delivered. Failed runs, layout misses and ads filtered out by monitor mode all cost nothing, and the `maxResults` setting is a hard ceiling, so a run can never bill beyond the cap you set.

Support: message via the Issues tab — responses within 24 hours on weekdays.

***

*Changelog — v2 (27 July 2026): corrected output schema to match verified live output; removed `landing_url`, `ad_start_date` and `ad_end_date`, which are not exposed in the card markup; added `ad_id`, `detail_url`, `promoter_name`, `is_personal_profile_ad` and `ad_copy_length`; added company-ID guidance; price set to $0.004; removed references to an examples folder that does not exist yet.*

# Actor input Schema

## `preset` (type: `string`):

One-click configurations. Selecting a preset fills sensible defaults; any field you set explicitly still wins.

## `queries` (type: `array`):

Company names, LinkedIn company URLs, or keywords to search the Ad Library for. Example: \["Salesforce", "hubspot.com", "crm software"]

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

Two-letter country code to filter where ads were shown (e.g. GB, US). Leave empty for all countries.

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

Hard cap on charged results across all queries.

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

ISO date (YYYY-MM-DD). Only ads last seen on or after this date.

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

ISO date (YYYY-MM-DD). Only ads first seen on or before this date.

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

Compares against your previous runs and returns only new or changed ads. You are charged only for those. Ideal for scheduled daily/weekly runs.

## `enrich` (type: `boolean`):

Adds derived fields: creative\_format, cta\_type, language, duplicate detection, first/last seen tracking. No extra charge.

## `aiAnalysis` (type: `boolean`):

Optional, separately charged per record: likely campaign objective, messaging style (performance vs brand), implied audience, creative themes. Off by default.

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

Proxy settings. Residential proxies recommended.

## Actor input object example

```json
{
  "preset": "none",
  "queries": [
    "Salesforce"
  ],
  "maxResults": 100,
  "onlyNew": false,
  "enrich": true,
  "aiAnalysis": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One record per LinkedIn ad, including advertiser, ad copy, headline, creative format, CTA type, language, media URLs and first/last seen timestamps.

# 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 = {
    "queries": [
        "Salesforce"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("interactapps/linkedin-ad-library-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 = { "queries": ["Salesforce"] }

# Run the Actor and wait for it to finish
run = client.actor("interactapps/linkedin-ad-library-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 '{
  "queries": [
    "Salesforce"
  ]
}' |
apify call interactapps/linkedin-ad-library-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,interactapps/linkedin-ad-library-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/kcfVmvxX2YglUSVcU/builds/0Os0AEEQsBAyoRcbb/openapi.json
