# LinkedIn Ad Library Scraper: Ads, Impressions & Targeting (`plain-signal/linkedin-ad-library-scraper`) Actor

Probe

- **URL**: https://apify.com/plain-signal/linkedin-ad-library-scraper.md
- **Developed by:** [Plain Signal](https://apify.com/plain-signal) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

### What does LinkedIn Ad Library Scraper do?

**LinkedIn Ad Library Scraper** extracts the ads any company runs on LinkedIn from the public [LinkedIn Ad Library](https://www.linkedin.com/ad-library): single image, video, carousel, document, article, message (InMail), event and job ads, searchable by **company name, website, LinkedIn company URL or keyword**.

For every ad you get the **full ad text, headline, call to action and landing page (with its UTM parameters)**, the image, video or carousel cards, who paid for it and, for ads shown in the EU, **run dates, total impressions, impressions by country and the targeting** the advertiser chose. Clean JSON, CSV or Excel. No LinkedIn account or cookies needed.

- 🎯 **Exact advertiser:** `HubSpot`, `hubspot.com` or `linkedin.com/company/hubspot` all return HubSpot's own ads, not the ads of every partner with "HubSpot" in its name.
- 📊 **Impressions and targeting:** impression ranges as numbers (`impressionsMin`, `impressionsMax`), country shares, and targeted locations, languages and criteria.
- 🔗 **Campaign tracking:** landing URL (LinkedIn `lnkd.in` short links resolved), landing domain and parsed `utm_*` parameters show which campaigns and funnels an ad belongs to.
- 🔔 **Monitor mode:** schedule it and get only competitors' new ads on every run.
- ✅ **Advertiser check:** one row per company: does it run LinkedIn ads, how many in the last 30 days, which formats.

### What can I use it for?

- 🕵️ **B2B competitor research:** see every offer, webinar, whitepaper and message your competitors push to your buyers, and how much reach each ad got.
- 📝 **Ad copy swipe files:** collect hundreds of real B2B ads in your niche as a spreadsheet, or feed them to an LLM to draft your own.
- 🎯 **Lead generation:** check a list of companies and find the ones spending on LinkedIn ads, a strong signal for agencies, SaaS sales and B2B marketers.
- 🔔 **Alerts:** get a Slack message or email when a competitor launches new LinkedIn ads.
- 🌍 **Market research:** search by keyword (e.g. `crm software`, `webinar`) and country to see who advertises in a category.

### How to use it

1. Enter one or more **companies**: names (`HubSpot`), websites (`hubspot.com`), LinkedIn company URLs or company IDs. Or enter **keywords** to find ads from any advertiser.
2. Optionally pick a **country** and a **date range**.
3. Click **Start**. Download the results as JSON, CSV or Excel, or get them through the API.

#### Advertiser check (lead lists)

Set **Mode** to *Advertiser check* and paste a list of companies or websites. You get one row per company with `isAdvertising`, the number of ads in the last 30 days (`adsLast30Days`, up to 100), the formats used and links to sample ads.

#### Get alerts for new ads (monitor mode)

Set **Monitor name** (e.g. `competitors`) and [schedule](https://docs.apify.com/platform/schedules) the Actor daily or weekly. Each run then returns **only ads it hasn't returned before** under that name. Connect it to Slack, email, Google Sheets, Make, Zapier or n8n through Apify integrations.

### Input example

```json
{
  "companies": ["HubSpot", "salesforce.com", "https://www.linkedin.com/company/pipedrive"],
  "keywords": ["crm software"],
  "country": "DE",
  "dateRange": "last-30-days",
  "maxAdsPerSearch": 100
}
```

### Output example

A real ad from a run on 2026-10-02 (country shares shortened):

```json
{
  "adId": "1515543043",
  "advertiserName": "HubSpot",
  "advertiserId": "68529",
  "advertiserUrl": "https://www.linkedin.com/company/68529",
  "paidBy": "HubSpot, Inc.",
  "format": "IMAGE",
  "formatLabel": "Single Image Ad",
  "postedBy": null,
  "headline": "Kostenlos anmelden",
  "adText": "Pipeline-Problem erkannt, Kampagne gestartet: in Minuten. Live-Demo mit HubSpot am 30. Sept.",
  "callToAction": "Mehr erfahren",
  "landingUrl": "https://hubs.la/Q04vVMsQ0?utm_campaign=EMEA&utm_source=linkedin&utm_medium=paid&utm_id=805100113&hsa_acc=517582366&...",
  "landingDomain": "hubs.la",
  "utm": {"campaign": "EMEA", "source": "linkedin", "medium": "paid", "id": "805100113"},
  "imageUrl": "https://media.licdn.com/dms/image/v2/D4D10AQFBkzQOBRPWCw/image-shrink_1280/...",
  "videoUrl": null,
  "carousel": [],
  "document": null,
  "firstShown": "2026-09-01",
  "lastShown": "2026-09-29",
  "impressions": "100k-150k",
  "impressionsMin": 100000,
  "impressionsMax": 150000,
  "impressionsByCountry": [
    {"country": "Germany", "percent": 65, "label": "65%"},
    {"country": "Switzerland", "percent": 18, "label": "18%"},
    {"country": "Austria", "percent": 17, "label": "17%"}
  ],
  "targeting": {
    "Language": {"includes": ["Deutsch"], "excludes": []},
    "Location": {"includes": ["Deutschland", "Österreich und die Schweiz"], "excludes": []}
  },
  "targetedBy": ["Audience", "Company", "Job"],
  "excludedBy": ["Audience", "Company"],
  "adUrl": "https://www.linkedin.com/ad-library/detail/1515543043",
  "searchInput": "HubSpot",
  "country": "DE",
  "scrapedAt": "2026-10-02T09:07:22+00:00"
}
```

Video ads also have `videoUrl` (MP4) and a thumbnail in `imageUrl`; carousel ads list their cards in `carousel`; document ads have the document title and page count in `document`.

### How much does it cost?

**$0.002 per ad** ($2 per 1,000 ads) with all details. **$0.001 per ad** with *Include ad details* turned off (text preview and image only). **$0.003 per company** in advertiser-check mode. No monthly fee, and you only pay for results.

| Use case | Results | Cost |
|---|---|---|
| One competitor, 100 latest ads | 100 | $0.20 |
| 10 competitors × 200 ads | 2,000 | $4.00 |
| Advertiser check for 500 companies | 500 | $1.50 |
| Weekly monitor of 5 competitors, ~30 new ads a week | ~120/month | ~$0.24/month |

Set **Max results in total** to cap the cost of a run.

### Good to know

- **Run dates, impressions and targeting** are published by LinkedIn for ads shown in the EU (Digital Services Act). For ads shown only outside the EU these fields are empty; the ad text, creative, advertiser, payer and landing page are always there.
- **Which advertiser is used for a name or website?** The advertiser whose name matches exactly (legal suffixes like *Inc.* or *GmbH* are ignored), for websites first the full domain (`monday.com`), then the name (`monday`). The run log says which LinkedIn company was used. If no advertiser has exactly that name, you get no ads (or `isAdvertising: false`) rather than a look-alike company, and the run log lists similar advertiser names: use one of them or the LinkedIn company URL.
- **Thought-leader ads:** ads a company runs through an employee's post have the company as advertiser and the employee's name in `postedBy`.
- **Message ads** contain LinkedIn's placeholders such as `%FIRSTNAME%`.
- **Coverage:** the Ad Library lists ads that ran on LinkedIn in the past year. Newest ads come first.
- **Speed:** about 150 ads with details per minute.
- The Actor reads public data only, doesn't log in and doesn't use cookies.

### FAQ

**Why are there fewer ads than I asked for?** The advertiser has no more ads for your filters (country, dates). Try *All countries* and *All dates*.

**Can I search ads by payer or for several countries at once?** Run one search per country; enter companies or keywords, and filter `paidBy` in the results.

**Something's wrong or missing?** Open an issue on the Issues tab. Requests are welcome.

# Actor input Schema

## `companies` (type: `array`):

Advertisers whose ads you want: company name (<code>HubSpot</code>), website (<code>hubspot.com</code>), LinkedIn company URL (<code>https://www.linkedin.com/company/hubspot</code>) or LinkedIn company ID (<code>68529</code>). A company URL or ID matches exactly; for names the Actor picks the advertiser with exactly that name.

## `keywords` (type: `array`):

Find ads from any advertiser that contain a word or phrase, e.g. <code>crm software</code> or <code>webinar</code>. Ignored in advertiser-check mode.

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

Only ads shown in this country.

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

Only ads that ran in this period. The Ad Library keeps ads for 1 year after they last ran.

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

Custom range start (overrides Date range).

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

Custom range end (overrides Date range).

## `maxAdsPerSearch` (type: `integer`):

Newest ads first.

## `maxItems` (type: `integer`):

Caps the cost of a run.

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

Full ad text, headline, call to action, landing URL with UTM parameters, video URL, run dates, impressions by country and targeting. Turn off for a faster, cheaper list of ads (text preview and image only).

## `mode` (type: `string`):

<b>Ads</b>: one row per ad. <b>Advertiser check</b>: one row per company: does it run LinkedIn ads, how many in the last 30 days, which formats. Good for lead lists.

## `monitorName` (type: `string`):

Set a name (e.g. <code>competitors</code>) and schedule the Actor: each run returns only ads it hasn't returned before under this name.

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

Leave empty: the Actor uses Apify Proxy (datacenter, residential on blocks) automatically.

## Actor input object example

```json
{
  "companies": [
    "HubSpot"
  ],
  "country": "ALL",
  "dateRange": "all",
  "maxAdsPerSearch": 100,
  "maxItems": 1000,
  "includeDetails": true,
  "mode": "ads",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Ads with text, headline, CTA, landing page, dates and impressions, as JSON, CSV or Excel.

## `allFields` (type: `string`):

Every field, including impressions by country, targeting, UTM parameters, carousel cards (and advertiser-check rows).

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

// Run the Actor and wait for it to finish
const run = await client.actor("plain-signal/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 = { "companies": ["HubSpot"] }

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

```

## MCP server setup

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