# LinkedIn Ad Library Scraper (`alexmorain/linkedin-ad-library-scraper`) Actor

Scrape the LinkedIn Ad Library without login: ad copy, creatives, payer, run dates, EU impressions and targeting as structured JSON. Search by advertiser, keyword, country or date. Pure HTTP, fast and cheap.

- **URL**: https://apify.com/alexmorain/linkedin-ad-library-scraper.md
- **Developed by:** [Alex Morain](https://apify.com/alexmorain) (community)
- **Categories:** Social media, AI
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.00 / 1,000 ad scrapeds

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

### What does LinkedIn Ad Library Scraper do?

LinkedIn Ad Library Scraper extracts ads from the public [LinkedIn Ad Library](https://www.linkedin.com/ad-library/home): ad copy, creatives, advertiser, payer, and, for ads served in the EU, **run dates, impressions and targeting criteria** parsed into structured fields. It works as a **LinkedIn Ad Library API** alternative: no login, no cookies, no browser automation.

It runs over **plain HTTP**, which makes it fast and cheap. It does not scrape private LinkedIn data, member profiles, or anything behind a login. It only reads what LinkedIn publishes in its ad transparency library.

### Why use LinkedIn Ad Library Scraper?

- **Competitive ad intelligence**: see every ad a competitor runs, with copy, creative, format, and how long it ran.
- **EU transparency data as structured fields**: most tools show you the ad; this one also parses the DSA transparency block, impressions range (total and per country) and targeting criteria (language, location, audience, company, job), into clean JSON.
- **Keyword search across the whole library**: find every advertiser using a phrase, not just ads of one company you already know.
- **Accurate date filtering**: LinkedIn silently ignores custom date ranges unless a specific parameter accompanies them. Scrapers that pass only the dates return the full corpus while claiming it is filtered. This one always sends the complete, verified parameter set. We measured it: an advertiser with 349 ads shows 21 for May 2026 when the filter is correctly applied, and 349 when it is not.
- **Complete pagination**: the library's last page omits its pagination marker. Parsers that require it stop early or crash. This one treats the absence as the end of the corpus and gets the full result set: 347 unique ads out of 349 announced in our reference measurement.
- Runs on the Apify platform: scheduling, REST API, webhooks, integrations, proxy rotation, and monitoring included.

### What data can LinkedIn Ad Library Scraper extract?

| Field | Type | Description |
|---|---|---|
| `advertiser`, `advertiser_url` | string | Advertising account and its LinkedIn page |
| `payer` | string | The "Paid for by" entity |
| `format` | string | Single Image Ad, Video Ad, Carousel Ad, Text Ad... |
| `headline`, `body` | string | Sponsored headline and full ad copy |
| `image_urls`, `video_urls` | array | Creative URLs (logos excluded) |
| `ran_from`, `ran_to` | string | First and last day the ad ran (EU-served ads) |
| `impressions_min`, `impressions_max` | number | Total impressions range, parsed (EU-served ads) |
| `impressions_by_country` | array | Impression share per country (EU-served ads) |
| `targeting_segments`, `targeting_parameters` | array, object | Targeting criteria selected by the advertiser (EU-served ads) |
| `promoted_by` | string | Company behind a Thought Leader Ad |

### How to scrape the LinkedIn Ad Library

1. Open the **Input** tab. One advertiser is already filled in, so you can press **Start** right away and see what comes out.
2. Replace it with the companies you want to watch. Use the slug from their LinkedIn page URL (`linkedin.com/company/`**`nvidia`**). One search runs per advertiser.
3. Optionally narrow by **countries**, **date range** or **payer**. LinkedIn applies these server-side, so narrowing makes the run faster and cheaper.
4. Keep a **Max ads per query** cap on your first run. A single large advertiser can be running several hundred ads, and you pay per ad returned. Set it to `0` once you know what you are getting.
5. Turn on **Include ad details** only for the advertisers you actually analyse: it adds impressions, targeting and full copy, at one extra request and a higher rate per ad.
6. Press **Start**, then download the dataset as JSON, CSV or Excel.

#### Which fields should I fill?

| If you want to... | Fill in | Leave alone |
|---|---|---|
| See what a competitor advertises | `advertisers`, a `maxAdsPerQuery` cap | everything else |
| Discover who advertises on a theme | `keyword` alone | `advertisers` |
| Measure EU reach and targeting | `advertisers`, `includeDetails: true`, an EU country | everything else |
| Track a campaign period | `startDate` + `endDate` | `dateOption` |
| Reproduce a filter this input lacks | `searchUrls` | everything else |

Fill at least one of `advertisers`, `keyword` or `searchUrls`. Everything else is optional.

### How much will it cost to scrape the LinkedIn Ad Library?

Pricing is pay-per-event: you pay a fixed price per ad, plus a tiny Actor start fee. Listing ads without details is the cheapest way to monitor volumes; enable details only when you need impressions, targeting, or full copy. A monitoring run that finds nothing new costs a fraction of a cent, which makes scheduled competitive monitoring affordable.

### Input

See the input tab for full configuration options. Three things worth knowing:

- `advertisers` accepts company names or slugs; each one becomes a separate server-side search.
- `keyword` works together with advertisers, or alone across the entire library.
- `startDate`/`endDate` go together and are automatically sent with the parameter LinkedIn requires to actually apply them.

### Output

You can download the dataset in various formats such as JSON, CSV, Excel, or HTML. Simplified example:

```json
[
  {
    "ad_id": "1234567890",
    "detail_url": "https://www.linkedin.com/ad-library/detail/1234567890",
    "advertiser": "Example Corp",
    "payer": "EXAMPLE CORP LTD",
    "format": "Video Ad",
    "headline": "Grow your pipeline with example insights",
    "body": "This is an example ad text presenting a product...",
    "image_urls": ["https://media.licdn.com/dms/image/..."],
    "ran_from": "Apr 23, 2026",
    "ran_to": "Apr 30, 2026",
    "impressions_display": "30k-50k",
    "impressions_min": 30000,
    "impressions_max": 50000,
    "impressions_by_country": [{ "country": "France", "share": "100%" }],
    "targeting_segments": ["Targeting includes English", "Targeting includes France"],
    "has_details": true
  }
]
```

### Tips

- Keep **Include ad details** off for large volume sweeps; turn it on for the advertisers you actually analyze. The event price differs, so you only pay for depth where you need it.
- Impressions and targeting exist **only for ads served in the EU** (Digital Services Act transparency). Ads shown only in the US or elsewhere return these fields as `null`; that is LinkedIn's data, not a scraper gap.
- The library serves roughly the **last 12 months** of ads.
- Use `maxAdsPerQuery` to cap costs on advertisers with thousands of ads.

### FAQ, disclaimers, and support

**Is it legal to scrape the LinkedIn Ad Library?** The Ad Library is LinkedIn's public ad transparency tool, published notably to satisfy the EU Digital Services Act. This Actor reads only that public library. Our Actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what has been chosen to be shared publicly. However, you should be aware that your results could contain personal data (e.g., the name of a person behind a Thought Leader Ad). Personal data is protected by the GDPR and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

**An advertiser returns zero ads.** Check the spelling of the company slug, and remember the library only covers ads from the last 12 months. Some companies advertise under a different account name than their brand.

**Impressions are empty.** The ad was not served in the EU; LinkedIn only publishes impressions and targeting for EU-served ads.

Found a problem or missing field? Open a ticket in the **Issues** tab, it is read. For programmatic access, see the **API** tab.

# Actor input Schema

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

Company names or LinkedIn company slugs, one per line: <code>nvidia</code>, <code>doctolib</code>. Each one becomes its own search, and the results carry the advertiser name so you can tell them apart.<br><br><b>How to be sure of a name:</b> open the company LinkedIn page, the slug is the last part of the URL (<code>linkedin.com/company/<b>nvidia</b></code>). Some groups advertise under a legal entity rather than their brand; if a search comes back empty, that is usually why.<br><br>Leave empty if you are searching by keyword across the whole library instead.

## `keyword` (type: `string`):

A word or phrase to search for in the ads themselves.<br><br>Used <b>alone</b>, it sweeps the entire Ad Library and finds every advertiser running that message: the way to discover competitors you had not listed. Used <b>together with advertisers</b>, it narrows each advertiser's ads to those mentioning it.<br><br>Leave empty to get all the ads of the advertisers above.

## `searchUrls` (type: `array`):

Full Ad Library search URLs, copied straight from your browser: <code>https://www.linkedin.com/ad-library/search?...</code><br><br>The escape hatch: build any filter combination by hand on the LinkedIn site, paste the resulting URL here, and the Actor reproduces it exactly. Useful for filters this input does not expose.<br><br>One caveat, and it is the reason most competing tools return wrong data: LinkedIn <b>silently ignores</b> a start and end date in a URL unless <code>dateOption=custom-date-range</code> is present too. A URL without it returns the whole corpus while looking filtered. Prefer the date fields below, which always send the complete parameter set.

## `countries` (type: `array`):

ISO 3166-1 alpha-2 codes of the countries where the ads were shown: <code>US</code>, <code>FR</code>, <code>DE</code>.<br><br>Leave empty for worldwide, which is the honest default when you do not know where a company advertises. Note that impressions and targeting data only exist for ads served in the <b>EU</b>, so an EU country here is what makes the richest fields appear.

## `dateOption` (type: `string`):

The period during which the ads ran. <b>The library only holds roughly the last 12 months</b>, whatever you ask for, so "All time" means "the last twelve months".<br><br>Ignored when you fill the two custom date fields below.

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

<code>YYYY-MM-DD</code>, within the last 12 months. Fill it together with the end date; either both or neither. It overrides the dropdown above.<br><br>The Actor always sends the extra parameter LinkedIn requires for a custom range to actually apply, so the filter you set is the filter you get.

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

<code>YYYY-MM-DD</code>. Goes together with the custom start date.

## `payer` (type: `string`):

Filter on the entity that paid for the ad, the "Paid for by" line: often a legal entity or an agency rather than the brand.<br><br>Useful to map a group whose subsidiaries advertise separately, or to find every brand handled by one agency. Leave empty in normal use.

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

Opens the detail page of every ad, which adds the <b>full ad copy</b>, the payer, the exact run dates and, for ads served in the EU, the <b>impressions</b> (total and per country) and the <b>targeting criteria</b> the advertiser selected.<br><br>Off by default because it costs one extra request per ad and is billed at a higher per-ad rate. The efficient pattern: sweep wide with it off to see who advertises and how much, then re-run with it on for the handful of advertisers you actually analyse.<br><br>Without it you still get advertiser, format, headline, creatives and a copy preview.

## `maxAdsPerQuery` (type: `integer`):

Stops each search after this many ads. The cap applies per search, so three advertisers with a cap of 100 can return up to 300 ads.<br><br><b>Keep a cap on your first run.</b> A single large advertiser can be running several hundred ads, and you pay per ad returned. 100 is enough to see the shape of a competitor's advertising; raise it once you know what you are getting.<br><br>Set <code>0</code>, or leave the field empty, for no limit at all.

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

Leave as is. Datacenter proxies are the default and are enough for the Ad Library; the Actor rotates sessions by itself when LinkedIn rate-limits. Switch to residential only if a large run keeps getting blocked.

## Actor input object example

```json
{
  "advertisers": [
    "nvidia",
    "doctolib"
  ],
  "keyword": "AI copilot",
  "countries": [
    "US"
  ],
  "dateOption": "all-time",
  "includeDetails": false,
  "maxAdsPerQuery": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing all scraped 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 = {
    "advertisers": [
        "nvidia"
    ],
    "countries": [
        "US"
    ],
    "maxAdsPerQuery": 100,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("alexmorain/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 = {
    "advertisers": ["nvidia"],
    "countries": ["US"],
    "maxAdsPerQuery": 100,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("alexmorain/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 '{
  "advertisers": [
    "nvidia"
  ],
  "countries": [
    "US"
  ],
  "maxAdsPerQuery": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call alexmorain/linkedin-ad-library-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alexmorain/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/rwt0cuqtskocjiAVy/builds/lXPLE3czZR7fs3zN8/openapi.json
