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

Extract LinkedIn ads from the LinkedIn Ad Library: creatives, impressions by country, targeting and paying entity. No login. Export CSV, JSON, Excel.

- **URL**: https://apify.com/rastriq/linkedin-ad-library-scraper.md
- **Developed by:** [Rastriq — Structured data from the world](https://apify.com/rastriq) (community)
- **Categories:** Social media, Lead generation
- **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 with full details

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

Extract structured advertising intelligence from the **LinkedIn Ad Library** — ad creatives, estimated impressions by country, targeting parameters and the legal entity that paid for each ad. No login, no cookies, no browser.

> 🎯 **The only LinkedIn ad scraper that doesn't bill you for the wrong advertiser.** Searching `HubSpot` on LinkedIn also returns *Sparkon | HubSpot Elite Partner*, *MAN Digital: HubSpot & RevOps Agency* and a dozen other partners — **26% noise** in our measurements. This Actor targets by company ID or filters by exact name, and drops the rest *before* fetching their detail pages, so you never pay for them.
>
> 🚀 **Try it free** — your first $5 of Apify usage is on the house. No credit card, no LinkedIn account.

***

### 📌 What is LinkedIn Ad Library Scraper?

The LinkedIn Ad Library is LinkedIn's public ad transparency archive, published under the EU Digital Services Act. It shows every ad an advertiser ran in the last 12 months — 25 at a time, behind an infinite scroll, with no export and no API.

**LinkedIn Ad Library Scraper** turns it into a dataset: the copy, video and image URLs, landing page, impression bucket, country split, the targeting the advertiser selected, and who paid the bill.

Typical uses: **competitive monitoring** (what's running right now, via `isActive`), **media agency mapping** (`payingEntity` reveals who runs a brand's paid social), **share of voice** (absolute impression estimates per country), **targeting teardowns**, and **creative libraries** of competitor copy, video and landing pages.

***

### 📋 What data does LinkedIn Ad Library Scraper extract?

| Field | Type | Description |
|---|---|---|
| 🆔 `adId` | string | LinkedIn's numeric ad ID — stable primary key |
| 🔗 `adUrl` | string | Direct link to the Ad Library detail page |
| 🏢 `advertiserName` / `advertiserId` / `advertiserUrl` | string | Company running the ad, plus its LinkedIn page |
| 💳 `payingEntity` | string | Legal entity that paid (often the media agency) |
| 🏷️ `creativeType` / `adFormat` | string | `SPONSORED_VIDEO`, `SPONSORED_STATUS_UPDATE`, `JOBS_V2`… / "Video Ad", "Single Image Ad"… |
| 📝 `commentary` | string | Full ad copy, line breaks preserved |
| 📰 `headline` / `callToAction` | string | Sponsored content headline and CTA label |
| 🌐 `destinationUrl` | string | Landing page (LinkedIn tracking stripped, UTMs kept) |
| 🎬 `videoUrls` / `imageUrls` / `documentPageUrls` | array | Direct media URLs for every creative asset |
| 🎠 `carouselCards` | array | Per-slide title, image and destination for Carousel Ads |
| 🔗 `commentaryLinks` | array | Links embedded in the body copy — often the real destination |
| 📅 `startDate` / `endDate` / `durationDays` | string / int | Normalised run period |
| 🟢 `isActive` | boolean | Whether the ad is still running today |
| 📈 `impressionsTotalRaw` / `Min` / `Max` | string / int | Published bucket (`100k-150k`) plus parsed bounds |
| 🌍 `impressionsByCountry` | array | Country, share, **and absolute estimate** (`estimatedMin`/`estimatedMax`) per market |
| 🎯 `targetingSegments` | array | Included / excluded values per parameter (Language, Location, …) |
| 🎛️ `targetingParameters` | array | Which parameter families were used to target or exclude |
| 🧩 `variants` | array | Full per-variant payload for multi-creative ads |

#### Ad formats covered

All 15 creative types LinkedIn's own frontend knows about, including the ones most scrapers flatten: **Carousel** (per-slide titles and destinations), **Event** (event name and CTA), **LinkedIn Article**, **Job posting**, **Document** (title plus page images), Single Image, Video, Message, Spotlight, Text and Follow Company ads. Unknown or new formats degrade gracefully to the universal extraction rather than returning empty.

> **Note:** impressions and targeting are only published for ads served in the EU region. Non-EU ads return `targetingAvailable: false` and null impressions — that is LinkedIn's limitation, not the scraper's.

***

### 🚀 How to use LinkedIn Ad Library Scraper

1. **Pick your advertisers.** Paste company URLs or IDs for exact targeting, or type names and set `advertiserMatch` (see the section above).
2. *(Optional)* **Paste a search URL instead.** Apply filters on `linkedin.com/ad-library/search`, copy the URL into **Ad Library URLs**. Filters in the URL win over the form fields.
3. **Narrow the search.** Countries, date range, impression bounds and targeting families map 1:1 to LinkedIn's own filters.
4. **Keep "Scrape ad details" on** to get impressions and targeting. Turn it off for a fast, cheap inventory of which ads exist.
5. **Set a proxy.** LinkedIn rate-limits per IP, so the default datacenter Apify Proxy plus 4–8 parallel sessions is the sweet spot. Residential is not needed: this site has no anti-bot.
6. Press **Start**, then export from the Output tab as JSON, CSV, Excel or feed it straight into your warehouse via the API.

#### Re-scrape mode

Paste known IDs into **Ad IDs** to refresh a fixed ad set daily without re-running the search — ideal for tracking how an impression bucket grows while a campaign is live.

***

### 🎯 Getting the right advertiser (and not paying for the rest)

LinkedIn's Ad Library matches advertiser names as a **substring**. A search for `HubSpot` returns 2,576 ads across a dozen advertisers; only 1,403 are actually HubSpot's. Everything else is partners and agencies with the brand in their name — and with pay-per-result pricing, that difference lands on your invoice.

LinkedIn Ad Library Scraper gives you three ways to fix it, in order of precision:

| Approach | How | Precision |
|---|---|---|
| **Company IDs** | `companyIds: ["68529"]` | Exact, filtered on LinkedIn's servers. Zero wasted requests |
| **Company URLs** | `companyUrls: ["https://www.linkedin.com/company/nvidia/"]` | Same as above — one extra request resolves the page to its numeric ID |
| **Name + matching mode** | `advertisers: ["HubSpot"]` + `advertiserMatch: "exact"` | Filtered client-side, before the detail page is fetched |

`advertiserMatch` has three modes: `any` (LinkedIn's default behaviour), `startsWith` (keeps sub-brands like *HubSpot for Developers*, drops partners) and `exact`.

Measured on identical 40-ad production runs:

| Mode | Ads delivered | Distinct advertisers | Precision | Requests used |
|---|---:|---:|---:|---:|
| `any` | 40 | 7 | 68% | 46 |
| `exact` | 40 | 1 | **100%** | **44** |

The precise run used *fewer* requests than the noisy one: the 22 discarded ads never had their detail page fetched.

The run log tells you exactly what it saved you:

```
Advertiser filter 'exact' dropped 7/27 ads (26% noise) before fetching
their detail pages — you were not charged for them.
```

***

### ⚙️ Input parameters for LinkedIn Ad Library Scraper

| Parameter | Type | Default | Description |
|---|---|---|---|
| `companyIds` | array | `[]` | Numeric LinkedIn company IDs — **exact, server-side targeting** |
| `companyUrls` | array | `[]` | Company pages, resolved to their numeric ID automatically |
| `advertisers` | array | `["astara"]` | Company names (`accountOwner`, substring match) |
| `advertiserMatch` | string | `any` | `any` / `startsWith` / `exact` — how strictly to match those names |
| `searchUrls` | array | `[]` | Full Ad Library search URLs with filters applied |
| `adIds` | array | `[]` | Ad IDs or detail URLs for re-scrape mode |
| `keyword` | string | — | Free-text search inside the creative |
| `payer` | string | — | Filter by paying entity |
| `countries` | array | `[]` | ISO-2 delivery countries |
| `dateOption` | string | `""` | `last-30-days`, `current-month`, `current-year`, `last-year` |
| `startDate` / `endDate` | string | — | Custom `YYYY-MM-DD` range (overrides the preset) |
| `impressionsMinValue` / `impressionsMaxValue` | integer | — | Impression bounds, with `thousand` / `million` units |
| `includedTargetingFacets` / `excludedTargetingFacets` | array | `[]` | Only ads that targeted (or excluded) these parameter families — filtered server-side |
| `scrapeAdDetails` | boolean | `true` | Fetch each ad's detail page |
| `maxAdsPerQuery` | integer | `200` | Ads per advertiser / URL (`0` = no limit) |
| `maxAdsTotal` | integer | `1000` | Hard cap for the whole run (`0` = no limit) |
| `proxyConfiguration` | object | Apify Proxy (datacenter) | Strongly recommended; residential only if you see 429s |
| `sessions` | integer | `4` | Parallel identities (one IP each) |
| `requestDelayMs` | integer | `2000` | Delay per session — see Performance below |
| `maxRetries` | integer | `4` | Retries on 429/5xx with exponential backoff |

***

### 📦 LinkedIn ads output example

```json
{
  "adId": "859756133",
  "adUrl": "https://www.linkedin.com/ad-library/detail/859756133",
  "scrapedAt": "2026-08-20T07:19:10+00:00",
  "advertiserName": "astara",
  "advertiserId": "1240549",
  "adFormat": "Video Ad",
  "creativeType": "SPONSORED_VIDEO",
  "payingEntity": "WPP MEDIA SPAIN, S.A.U.",
  "commentary": "🚗 At #Astara, we keep strengthening our mobility ecosystem!\n\nWe're proud to celebrate another milestone…",
  "startDate": "2025-10-01",
  "endDate": "2025-10-14",
  "durationDays": 14,
  "impressionsTotalRaw": "100k-150k",
  "impressionsTotalMin": 100000,
  "impressionsTotalMax": 150000,
  "impressionsByCountry": [
    { "country": "Spain",    "sharePct": 30, "shareRaw": "30%",  "isUpperBound": false },
    { "country": "Colombia", "sharePct": 26, "shareRaw": "26%",  "isUpperBound": false },
    { "country": "Chile",    "sharePct": 24, "shareRaw": "24%",  "isUpperBound": false },
    { "country": "India",    "sharePct": 1,  "shareRaw": "< 1%", "isUpperBound": true }
  ],
  "targetingSegments": [
    { "parameter": "Language", "included": ["English"], "excluded": [] },
    { "parameter": "Location", "included": ["Peru", "Chile", "Colombia", "Spain"], "excluded": [] }
  ],
  "videoUrls": ["https://dms.licdn.com/playlist/vid/v2/…/mp4-720p-30fp-crf28/…"],
  "targetingAvailable": true,
  "detailScraped": true
}
```

***

### ⚡ Performance and LinkedIn rate limits

LinkedIn's Ad Library applies a **token bucket per IP**: roughly five requests in a burst, then HTTP 429 with a JavaScript challenge. Measured on a clean IP:

| Delay per session | Result |
|---|---|
| 2000 ms | 0 rate limits over 20 consecutive requests ✅ |
| 1500 ms | ~10% of requests hit 429 |
| < 1000 ms | throttled almost immediately |

Because the limit is per IP, **throughput scales with proxies, not with concurrency** — each parallel session gets its own IP.

With 8 sessions at 2000 ms and details on, that is roughly **7,000 ads/hour**. Each session keeps its own IP and cookie jar, backs off adaptively, and is recycled onto a fresh IP after repeated 429s.

***

### 💰 How much does it cost to use LinkedIn Ad Library Scraper?

LinkedIn Ad Library Scraper is **pay-per-event**: you pay per ad returned, with no monthly rental. Prices drop automatically with your Apify plan.

| Event | Free | Bronze | Silver | Gold+ |
|---|---:|---:|---:|---:|
| **Ad with full details** | $2.00 / 1K | $1.20 / 1K | $0.90 / 1K | **$0.50 / 1K** |
| **Ad preview** (`scrapeAdDetails: false`) | $0.50 / 1K | $0.30 / 1K | $0.25 / 1K | $0.15 / 1K |
| Actor start | $0.00005 per GB of memory, once per run | | | |

**Ads dropped by the advertiser filter are never charged**, and the run is capped to your budget *before* scraping starts — so it never fetches pages you can't pay for.

#### Why the list price isn't the price you pay

The cheapest LinkedIn ad scrapers charge less per ad but hand you whatever LinkedIn's substring search returns. In our measurements that is **26% wrong advertiser** — partners and agencies with the brand in their name. You pay for those too.

Compare on what actually matters, the cost of a **correct** ad:

| | Cheapest competitor | LinkedIn Ad Library Scraper |
|---|---:|---:|
| List price (Free tier) | $1.50 / 1K | $2.00 / 1K |
| Ads that are the advertiser you asked for | 74% | **100%** |
| **Cost per correct ad** | **$2.03 / 1K** | **$2.00 / 1K** |

The same holds at every discount tier. A higher list price on cleaner data works out cheaper — and you skip the work of filtering the noise out yourself afterwards.

> 💡 **Tip:** start with `maxAdsPerQuery: 20` to size your own numbers, then scale. You can cap spend per run with the Apify budget limit at any time.

#### Is scraping the LinkedIn Ad Library free?

Your first $5 of Apify credit covers roughly **2,500 fully detailed ads** — enough for a complete competitive audit of a mid-size advertiser at no cost.

#### What does it cost us to run?

For transparency: 0.064 compute units and ~11 MB of datacenter proxy traffic per 1,000 ads, measured on the platform. Full methodology in [`docs/EFFICIENCY.md`](docs/EFFICIENCY.md).

***

### 🔗 Related Rastriq Actors

Pair it with the rest of the [Rastriq ad-intelligence portfolio](https://apify.com/rastriq):

| Actor | What it adds |
|---|---|
| [Facebook Ad Library Scraper](https://apify.com/rastriq/fb-adlibrary-scraper) | The same competitive-ads intelligence for Facebook and Instagram |
| [TikTok Ad Library Scraper](https://apify.com/rastriq/tiktok-ad-library-scraper) | TikTok's EU ad transparency archive, same output shape |
| [Google Ads Transparency Scraper](https://apify.com/rastriq/google-ads-scraper) | Search, Display and YouTube ads to close the cross-channel picture |
| [SimilarWeb Data Extractor](https://apify.com/rastriq/similarweb-data-extractor) | Traffic context for the landing pages these ads point to |

***

### 🔄 Setting up recurring monitoring with LinkedIn Ad Library Scraper

1. **Save your input as a Task** in Apify Console, then open **Schedules**.
2. **Set the frequency** — daily, weekly, or a cron expression (`0 8 * * 1` = every Monday at 8am).
3. **Add a webhook** on run finish to push new ads into Slack, email or your own endpoint.
4. **Use Ad IDs mode** to re-scrape a fixed ad set and watch impression buckets grow while a campaign is live.

***

### ❓ Frequently Asked Questions about scraping LinkedIn ads

#### Is scraping the LinkedIn Ad Library legal?

It only accesses **publicly available data** — the ad transparency archive LinkedIn publishes under the EU Digital Services Act, visible to anyone without logging in. The Actor honours `robots.txt` and paces requests (one every two seconds per IP) so it never loads LinkedIn's servers.

No personal data is collected: every field describes an advertisement or a company. You remain responsible for your use case complying with GDPR, CCPA and LinkedIn's Terms of Service. See [Apify's guide on the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

#### Do I need a LinkedIn account or cookies?

No. The Ad Library is served by LinkedIn's guest frontend and returns fully rendered HTML to anonymous requests. Never put your `li_at` session cookie into a scraper — it risks your personal account and is not needed here.

#### Is the data personal?

No. Every field describes an *advertisement* or a *company* — creative, spend proxy, targeting, paying entity. No names, emails, phone numbers or profiles of individuals are collected.

#### Why do some ads have no impressions or targeting?

LinkedIn publishes those fields only for ads served in the EU region, under the Digital Services Act. Ads outside that scope come back with `targetingAvailable: false`.

#### Why did I get fewer ads than the "N ads match your search" counter?

The counter is an estimate computed before deduplication; the paginated result set is the ground truth. The Actor deduplicates by `adId` across pages and queries.

#### How far back does the archive go?

LinkedIn only indexes ads created in the last 12 months. Anything older is gone from the source.

Enable Apify Proxy, or raise `requestDelayMs` to 3000. Without a proxy the Actor forces `sessions: 1`, because extra sessions would share one IP and just burn the same bucket faster. If the 429s persist on datacenter IPs, switch `proxyConfiguration` to the `RESIDENTIAL` group.

#### How do I integrate LinkedIn Ad Library Scraper with my stack?

Natively with **Make** and **Zapier**, export to **Google Sheets**, **webhooks** on run finish, **scheduled runs**, and the **Apify API** from any language — see the API tab.

#### I found a bug or my run failed. Where do I report it?

Open a ticket in the **Issues tab** with your input and the run ID. If a run returned 0 ads, the raw HTML of the failing search is saved to the key-value store as `debug_search_page` — attach it and diagnosis is much faster.

# Actor input Schema

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

Paste URLs straight from the <b>LinkedIn Ad Library</b>. Build your search there with the filters you know, copy the URL, paste it here — every filter is preserved.<br><br>Accepted:<br>• <code>https://www.linkedin.com/ad-library/search?accountOwner=nike</code> — search<br>• <code>https://www.linkedin.com/ad-library/detail/1234567890</code> — single ad<br>• <code>https://www.linkedin.com/company/nike/</code> — company page (resolved to an exact ID)<br><br>💡 This is the fastest path. Everything below is optional.

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

Company names, if you would rather not paste URLs. One per line.<br><br>⚠️ Name search is a substring match on LinkedIn's side, so <code>HubSpot</code> also returns its partner agencies. The <b>Advertiser match</b> setting handles that and defaults to <code>Starts with</code>, which drops them <b>before</b> you are charged.<br><br>💡 For exact results use <b>Company IDs</b> or <b>Company URLs</b> below.

## `maxAdsTotal` (type: `integer`):

Maximum ads to return.<br><br>• <b>20–50</b> — quick preview<br>• <b>500–2.000</b> — one brand, full history<br>• <b>0</b> — no limit<br><br>💡 Start small to size the cost, then scale.

## `scrapeAdDetails` (type: `boolean`):

Fetch each ad's detail page: <b>impressions</b>, <b>impressions by country</b>, <b>targeting</b>, <b>paying entity</b> and run dates (EU DSA data).<br><br>Turn it off for a faster, cheaper listing with just advertiser, copy preview and format.

## `companyIds` (type: `array`):

Numeric LinkedIn company IDs. <b>This is the precise way to target an advertiser.</b><br><br>LinkedIn's name search is a substring match, so <code>HubSpot</code> also returns <i>Sparkon | HubSpot Elite Partner</i>, <i>MAN Digital: HubSpot & RevOps Agency</i> and a dozen more partners — measured at <b>26% noise</b>. Company IDs filter server-side with zero noise and zero wasted requests.<br><br>💡 Don't know the ID? Paste the company page in <b>Company URLs</b> below and the Actor resolves it for you.

## `companyUrls` (type: `array`):

LinkedIn company pages, e.g. <code>https://www.linkedin.com/company/nvidia/</code>.<br><br>Each one costs a single extra request and is resolved to its numeric company ID, so the search is then <b>exact</b> — unlike Actors that just search the company name.

## `advertiserMatch` (type: `string`):

How strictly the advertiser name must match.<br><br>• <b>Starts with</b> (default) — keeps <code>HubSpot</code> and <code>HubSpot for Developers</code>, drops <code>Sparkon | HubSpot Elite Partner</code>. Measured on a live run: name search returns <b>32% partner noise</b>, and this setting removes it <b>before</b> the detail page is fetched, so you are never charged for it.<br>• <b>Exact</b> — only the identical name.<br>• <b>Any</b> — no filtering. You pay for every substring match LinkedIn returns.<br><br>💡 Ignored when you search by <b>Company IDs</b> or <b>Company URLs</b>: those already match exactly on LinkedIn's side.

## `adIds` (type: `array`):

Re-scrape mode: refresh known ads without searching again. Accepts raw IDs (<code>859756133</code>) or detail URLs (<code>https://www.linkedin.com/ad-library/detail/859756133</code>).<br><br>💡 Useful for daily impression tracking of a fixed ad set.

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

Free-text search inside the ad creative. Combines with the advertiser filter.

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

Filter by the legal entity that paid for the ad (<code>payer</code>). Useful to map which media agency runs a brand's campaigns.

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

Only return ads served in these countries. Leave empty for all.<br><br>💡 <b>Tip:</b> this is a <b>delivery</b> filter, not the advertiser's HQ.

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

Preset period. Leave as <b>Any time</b> and use the custom dates below for full control.<br><br>⚠️ LinkedIn only indexes ads created in the last 12 months.

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

Custom range start (<code>YYYY-MM-DD</code>). Overrides the preset above.

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

Custom range end (<code>YYYY-MM-DD</code>).

## `impressionsMinValue` (type: `integer`):

Lower bound of the estimated impression range.<br><br>⚠️ EU-region ads only — LinkedIn publishes impressions under the DSA.

## `impressionsMinUnit` (type: `string`):

Multiplier applied to the minimum impressions value.

## `impressionsMaxValue` (type: `integer`):

Upper bound of the estimated impression range.

## `impressionsMaxUnit` (type: `string`):

Multiplier applied to the maximum impressions value.

## `includedTargetingFacets` (type: `array`):

Only return ads where the advertiser <b>targeted</b> these parameter families.<br><br>💡 This filters on LinkedIn's side, so you never pay for the ads it excludes.<br><br>⚠️ EU-region ads only — targeting is a DSA disclosure.

## `excludedTargetingFacets` (type: `array`):

Only return ads where the advertiser <b>excluded</b> these parameter families.

## `unifiedFieldsOnly` (type: `boolean`):

Return only the fields shared by every ad library (Meta, Google, TikTok, LinkedIn), dropping the LinkedIn-specific ones (<code>li\_impressions\_by\_country</code>, <code>li\_targeting\_segments</code>, <code>li\_paying\_entity</code>…).<br><br>💡 Turn this on when you merge this dataset with other ad platforms and want one stable set of columns. Leave it off to keep LinkedIn's DSA data.

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

Stop after N ads per advertiser / URL. <code>0</code> = no limit.<br><br>⚠️ <b>0 can produce thousands of requests.</b> The default keeps API, task and scheduled runs bounded; raise it for full backfills.

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

LinkedIn rate-limits the Ad Library <b>per IP</b> (~1 request every 2 s). Proxies are the only way to go faster: each parallel session gets its own IP.<br><br>💡 <b>Leave it on the default datacenter proxy</b> — this site has no anti-bot, only per-IP rate limiting, and datacenter is far cheaper. Switch to <b>RESIDENTIAL</b> only if you see sustained 429s.

## `sessions` (type: `integer`):

Independent browsing identities (one proxy IP + cookie jar each). Throughput ≈ <code>sessions ÷ (delay in seconds)</code>.<br><br>Recommended:<br>• <b>1</b> — no proxy<br>• <b>4–8</b> — with Apify Proxy<br>• <b>12+</b> — large runs on residential proxies

## `requestDelayMs` (type: `integer`):

Milliseconds between two requests <b>of the same session</b>.<br><br>Measured behaviour:<br>• <b>2000 ms</b> — 0 rate limits (recommended)<br>• <b>1500 ms</b> — ~10% of requests get 429<br>• <b><1000 ms</b> — throttled immediately

## `maxRetries` (type: `integer`):

Retries per request on 429/5xx/network errors, with exponential backoff.

## Actor input object example

```json
{
  "searchUrls": [
    "https://www.linkedin.com/ad-library/search?accountOwner=hubspot"
  ],
  "maxAdsTotal": 50,
  "scrapeAdDetails": true,
  "companyIds": [],
  "companyUrls": [],
  "advertiserMatch": "startsWith",
  "adIds": [],
  "countries": [],
  "dateOption": "",
  "impressionsMinUnit": "thousand",
  "impressionsMaxUnit": "thousand",
  "includedTargetingFacets": [],
  "excludedTargetingFacets": [],
  "unifiedFieldsOnly": false,
  "maxAdsPerQuery": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "sessions": 4,
  "requestDelayMs": 2000,
  "maxRetries": 4
}
```

# Actor output Schema

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

All scraped ads with creative, impressions, targeting and paying entity.

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

Counters of scraped items, HTTP requests, retries and rate limits.

# 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 = {
    "searchUrls": [
        "https://www.linkedin.com/ad-library/search?accountOwner=hubspot"
    ],
    "maxAdsTotal": 50,
    "companyIds": [],
    "companyUrls": [],
    "adIds": [],
    "countries": [],
    "includedTargetingFacets": [],
    "excludedTargetingFacets": [],
    "maxAdsPerQuery": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("rastriq/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 = {
    "searchUrls": ["https://www.linkedin.com/ad-library/search?accountOwner=hubspot"],
    "maxAdsTotal": 50,
    "companyIds": [],
    "companyUrls": [],
    "adIds": [],
    "countries": [],
    "includedTargetingFacets": [],
    "excludedTargetingFacets": [],
    "maxAdsPerQuery": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("rastriq/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 '{
  "searchUrls": [
    "https://www.linkedin.com/ad-library/search?accountOwner=hubspot"
  ],
  "maxAdsTotal": 50,
  "companyIds": [],
  "companyUrls": [],
  "adIds": [],
  "countries": [],
  "includedTargetingFacets": [],
  "excludedTargetingFacets": [],
  "maxAdsPerQuery": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call rastriq/linkedin-ad-library-scraper --silent --output-dataset

```

## MCP server setup

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