# LinkedIn Ads Scraper (`solidcode/linkedin-ads-scraper`) Actor

\[💰 $0.5 / 1K] Extract ads from LinkedIn's public Ad Library — advertiser, headline, body, format, dates, impressions, CTAs. Search by keyword, advertiser, country, and date range. Optional detail enrichment for impressions-per-country and targeting.

- **URL**: https://apify.com/solidcode/linkedin-ads-scraper.md
- **Developed by:** [SolidCode](https://apify.com/solidcode) (community)
- **Categories:** Social media, Lead generation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 advertisement without details

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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Ads Scraper

Extract competitor ads from LinkedIn's public Ad Library at scale. Get advertiser, headline, body copy, creative format, image and video URLs, dates active, impression ranges, and (for EU-served ads) full targeting and country-level impressions. Perfect for B2B competitive intelligence, ad creative inspiration, brand monitoring, and marketing research.

### Why This Scraper?

- **Public Ad Library data, structured** — Every ad LinkedIn discloses in its transparency portal, returned as clean JSON rows ready for analysis
- **Three flexible search modes** — Search by keyword, by advertiser company, or by pasting any LinkedIn Ad Library URL directly. Combine all three in a single run
- **40+ countries supported** — Filter ads by where they were served, from the US and UK to Germany, India, Japan, Brazil, and the UAE
- **Optional EU detail enrichment** — Turn on detail mode to get country-level impression breakdowns and full targeting (languages, locations, audience parameters) for ads served in the EU under the Digital Services Act transparency rules
- **Tiered pay-per-event pricing** — $0.50 per 1,000 basic ads, $0.90 per 1,000 enriched ads. You only pay per ad returned — no compute or platform fees
- **Date-range filters** — Last 30 days, this month, this year, last year, or any custom 12-month window
- **Bulk-friendly** — Run dozens of keyword and advertiser searches in a single execution; results are deduplicated by ad ID across queries
- **All ad formats included** — Single image, video, carousel, document, message, spotlight, text, and thought-leader ads, each tagged with a clean `format` enum

### Use Cases

**Competitive Intelligence**
- Monitor every ad your competitors run on LinkedIn, including paused campaigns
- Track which messaging, headlines, and CTAs your industry is testing this quarter
- Spot new product launches by watching competitors' ad volume spike

**Ad Creative Research**
- Pull thousands of ad creatives by topic ("AI", "cybersecurity", "fintech") for inspiration
- Build a swipe file of high-performing B2B ad copy across formats
- Compare image vs video vs document ad strategies in your niche

**Brand Monitoring**
- Watch for competitors targeting your brand keywords
- Detect partner or reseller ads that misrepresent your product
- Audit your own agency's live campaigns from the public viewer

**Lead Generation & Sales Intelligence**
- Identify which companies are actively running paid LinkedIn campaigns (a strong intent signal)
- Build prospect lists of advertisers in specific verticals or geographies
- Surface ad agencies and SaaS vendors actively investing in growth

**Market & Trend Research**
- Quantify ad spend trends by geography or industry over time
- Map which message frames dominate B2B marketing right now
- Feed datasets into BI dashboards for client-facing reporting

### Getting Started

#### Example A — Simple keyword search

The fastest way to get started. Enter one or more keywords; each runs its own search and the results are merged.

```json
{
    "keywords": ["marketing automation", "sales enablement"],
    "maxResults": 500
}
````

#### Example B — Advertiser-scoped, multi-country, with date filter

Pull every ad a competitor ran in the US and UK over the last year. The slug is the part after `linkedin.com/company/` in their company URL.

```json
{
    "advertisers": ["hubspot", "salesforce"],
    "countries": ["US", "GB"],
    "dateOption": "last-year",
    "maxResults": 2000
}
```

#### Example C — Detail-enriched run for EU advertisers

Turn on `fetchDetails` to capture per-country impression ranges and full targeting (languages, locations, audience parameters) for ads served in the EU. Non-EU ads still return — they're charged at the basic tier since LinkedIn doesn't disclose extra data for them.

```json
{
    "keywords": ["b2b saas"],
    "countries": ["DE", "FR", "NL", "ES", "IT"],
    "dateOption": "last-30-days",
    "fetchDetails": true,
    "maxResults": 1000
}
```

#### Example D — Bulk via Start URLs

Already built a search in the LinkedIn Ad Library UI? Paste the URL directly — every filter is preserved.

```json
{
    "startUrls": [
        "https://www.linkedin.com/ad-library/search?keyword=cybersecurity&countries=US",
        "https://www.linkedin.com/ad-library/search?accountOwner=nvidia&dateOption=last-year"
    ],
    "maxResults": 5000
}
```

#### Example E — Custom date range

Pull ads active in a specific six-week window. Both dates must fall within the last 12 months (LinkedIn's retention limit).

```json
{
    "keywords": ["generative ai"],
    "dateOption": "custom-date-range",
    "startDate": "2026-02-01",
    "endDate": "2026-03-15",
    "maxResults": 1000
}
```

### Input Reference

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `keywords` | string\[] | `[]` | Free-text search terms (e.g. "AI marketing", "crypto"). Each keyword runs its own search and the results are combined |
| `advertisers` | string\[] | `[]` | LinkedIn company slugs (e.g. "nvidia", "microsoft", "hubspot"). The slug comes from the LinkedIn company URL — `linkedin.com/company/<slug>`. Use the slug from the URL, not a display name like "Microsoft Corp" |
| `startUrls` | string\[] | `[]` | Paste full LinkedIn Ad Library search URLs directly. Bypasses the keyword and advertiser fields above |
| `countries` | string\[] | `[]` | Restrict results to ads served in selected countries. 40+ supported (US, GB, CA, DE, FR, JP, BR, IN, AE, and more). Empty = all countries |
| `dateOption` | string | `"last-30-days"` | Time window. One of: `last-30-days`, `current-month`, `current-year`, `last-year`, `custom-date-range` |
| `startDate` | string | `null` | Custom start date in `YYYY-MM-DD` format. Only used when `dateOption` is `custom-date-range`. Must be within the last 12 months |
| `endDate` | string | `null` | Custom end date in `YYYY-MM-DD` format. Only used when `dateOption` is `custom-date-range`. Must be within the last 12 months |
| `fetchDetails` | boolean | `false` | When enabled, opens each ad's detail page to extract impressions-per-country and full targeting. Increases per-ad price for ads where extra data is actually available (typically EU-served ads) |
| `maxResults` | integer | `1000` | Cap the total number of ads returned across all queries combined. Set to `0` for unlimited (each query is internally capped at ~4,800 ads by LinkedIn's pagination depth — split popular keywords across narrower searches if you need more) |

### Output

Each run pushes one row per ad. Two record shapes are possible — a basic search-card record, and (when `fetchDetails: true`) a record enriched with detail-page fields.

#### Basic record (search-card data, `fetchDetails: false`)

```json
{
    "recordType": "ad",
    "adId": "1281881684",
    "adLibraryUrl": "https://www.linkedin.com/ad-library/detail/1281881684",
    "advertiserName": "Maxio",
    "advertiserSlug": null,
    "advertiserUrl": null,
    "advertiserLogoUrl": "https://media.licdn.com/dms/image/v2/C4E0BAQE361-JB8cBLA/company-logo_100_100/0/1649952212473/wearemaxio_logo",
    "paidBy": null,
    "format": "image",
    "creativeType": "SPONSORED_STATUS_UPDATE",
    "headline": "Download Maxio Institute's Latest Report",
    "headlineDescription": null,
    "body": "In the realm of SaaS, benchmarks are more than just numbers — they're game-changers. Here's why...",
    "imageUrl": "https://media.licdn.com/dms/image/v2/D5610AQFymJR7uHth1w/image-shrink_1280/B56Z3FO9k9HQAc-/0/1777130527273",
    "videoUrl": null,
    "clickUrl": null,
    "country": null,
    "firstSeen": null,
    "lastSeen": null,
    "impressionsRange": null,
    "impressionsPerCountry": null,
    "targeting": null,
    "detailsFetched": false,
    "query": "keyword: marketing automation",
    "scrapedAt": "2026-04-27T15:42:01Z"
}
```

`advertiserSlug` and `advertiserUrl` are populated only when `fetchDetails: true` — LinkedIn dropped the company link from search cards in late 2026, so the link is read from each ad's detail page.

#### Detail-enriched record (EU ad with `fetchDetails: true`)

```json
{
    "recordType": "ad",
    "adId": "1389159976",
    "adLibraryUrl": "https://www.linkedin.com/ad-library/detail/1389159976",
    "advertiserName": "Niketa Calame-Harris, MFA",
    "advertiserSlug": "niketacalame",
    "advertiserUrl": "https://www.linkedin.com/in/niketacalame",
    "advertiserLogoUrl": "https://media.licdn.com/dms/image/v2/D4D03AQ.../profile-displayphoto.jpg",
    "paidBy": "The Harris Tech Pivot",
    "format": "image",
    "creativeType": "SPONSORED_STATUS_UPDATE",
    "headline": "Welcome to The Harris Tech Pivot",
    "headlineDescription": null,
    "body": "Bridging the gap between underrepresented talent and tech opportunity.",
    "imageUrl": "https://media.licdn.com/dms/image/v2/D4D22AQ.../feedshare-shrink_2048_1536.jpg",
    "videoUrl": null,
    "clickUrl": "https://harristechpivot.example.com/welcome",
    "country": null,
    "firstSeen": "2026-04-10",
    "lastSeen": "2026-04-14",
    "impressionsRange": {"min": 1000, "max": 5000},
    "impressionsPerCountry": null,
    "targeting": {
        "languages": ["English"],
        "locations": ["City of Johannesburg", "United States"],
        "locationsExcluded": ["India", "Europe", "Accra"],
        "parameters": {
            "Audience": {"targeted": false, "excluded": false},
            "Demographic": {"targeted": true, "excluded": false},
            "Company": {"targeted": false, "excluded": false},
            "Education": {"targeted": false, "excluded": false},
            "Job": {"targeted": true, "excluded": false},
            "Member Interests and Traits": {"targeted": false, "excluded": false}
        }
    },
    "detailsFetched": true,
    "query": "advertiser: nike",
    "scrapedAt": "2026-04-27T15:42:14Z"
}
```

`impressionsPerCountry` is populated only when LinkedIn renders the per-country breakdown in the detail page — typically EU ads with significant cross-country reach. Many EU ads serve in only one country and return `null` for this field.

#### Output Field Reference

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | string | Always `"ad"`. Discriminator for downstream pipelines that may receive other record kinds in the future |
| `adId` | string | LinkedIn's unique ad identifier |
| `adLibraryUrl` | string | Public Ad Library detail page URL |
| `advertiserName` | string | Display name of the advertiser (company or member) |
| `advertiserSlug` | string | null | LinkedIn identifier from the advertiser's URL — either a numeric company id (e.g. `"2029"`) or a member vanity slug (e.g. `"niketacalame"`). Populated only when `fetchDetails: true` |
| `advertiserUrl` | string | null | Full LinkedIn URL of the advertiser's company or member page. Populated only when `fetchDetails: true` |
| `advertiserLogoUrl` | string | null | Advertiser's logo / profile image URL |
| `paidBy` | string | null | Legal entity that paid for the ad. Populated when `fetchDetails: true` and LinkedIn discloses it |
| `format` | string | Ad format enum: `image`, `video`, `carousel`, `document`, `message`, `spotlight`, `text`, `thoughtleader`, or `unknown` |
| `creativeType` | string | null | LinkedIn's internal creative type (e.g. `SPONSORED_STATUS_UPDATE`, `SPONSORED_VIDEO`). Preserved as-is for advanced filtering |
| `headline` | string | null | Primary headline shown on the ad |
| `headlineDescription` | string | null | Secondary headline / description line. Often `null` — LinkedIn rarely renders a sub-headline in current UI |
| `body` | string | null | Main ad body copy. Newlines preserved for multi-paragraph copy |
| `imageUrl` | string | null | Ad creative image URL |
| `videoUrl` | string | null | Ad video URL (HLS playlist) — present for video ads |
| `clickUrl` | string | null | External destination URL the ad links to. Populated only when `fetchDetails: true` |
| `country` | string | null | Reserved for future use — currently always `null`. LinkedIn doesn't tag individual ads with a country on the search card; the `countries` filter is a page-level constraint |
| `firstSeen` | string | null | First date the ad was active, `YYYY-MM-DD`. Populated only when `fetchDetails: true` |
| `lastSeen` | string | null | Last date the ad was active, `YYYY-MM-DD`, or `null` if still running. Populated only when `fetchDetails: true` |
| `impressionsRange` | object | null | Total impressions range as `{"min": int, "max": int}` (e.g. `{"min": 10000, "max": 50000}`). Populated only when `fetchDetails: true` AND LinkedIn discloses the range |
| `impressionsPerCountry` | object | null | Per-country impressions: `{ "Country Name": {"min": int, "max": int}, ... }`. Populated only for EU ads with multi-country reach when `fetchDetails: true`. Often `null` even on EU ads |
| `targeting` | object | null | EU-only targeting breakdown — `{ languages: string[], locations: string[], locationsExcluded: string[], parameters: { "<facet>": {"targeted": bool, "excluded": bool} } }`. `locations` lists the regions/countries the advertiser targeted; `locationsExcluded` lists the regions/countries explicitly excluded from the audience. The `parameters` map keys come from LinkedIn's facet labels (e.g. `Audience`, `Demographic`, `Company`, `Education`, `Job`, `Member Interests and Traits`); `targeted: true` means the advertiser used that facet to include people, `excluded: true` means they used it to exclude people. Populated only when `fetchDetails: true` AND the detail page contained the EU "Ad Targeting" section |
| `detailsFetched` | boolean | `true` when the ad's detail page contained the EU "Ad Targeting" section (so the higher pricing tier was applied); `false` otherwise. With `fetchDetails: false` this is always `false` |
| `query` | string | The search term, advertiser slug, or URL label that produced this row (e.g. `"keyword: marketing automation"`, `"advertiser: hubspot"`, `"URL: https://..."`) |
| `scrapedAt` | string | ISO-8601 UTC timestamp when the row was captured |

When `fetchDetails: true`, the actor opens each ad's detail page regardless of where it ran. That means `advertiserUrl`, `advertiserSlug`, `paidBy`, `firstSeen`, `lastSeen`, and `clickUrl` populate for every ad — even ads that don't qualify for the higher pricing tier (US ads, etc.). You're only billed at the detail tier for ads where LinkedIn actually disclosed the EU "Ad Targeting" section.

### Tips for Best Results

#### Cast a wider net with multiple keywords

LinkedIn's search ranks results by relevance; try several related keywords (e.g. `"marketing automation"`, `"marketing platform"`, `"demand generation tool"`) to surface more ads in your space. Results are deduplicated by ad ID across queries — there's no double-charging.

#### Narrow by country to reduce noise

Without a `countries` filter you'll get every market — useful for global brands, less useful when you only care about North America. Add 1–3 countries to keep results focused.

#### Use `fetchDetails` selectively

Detail enrichment costs more per ad (`$0.90 vs $0.50` per 1,000) but only delivers extra data for EU-served ads under the Digital Services Act. Turn it on when:

- Your `countries` filter includes EU markets (DE, FR, NL, ES, IT, BE, PT, SE, NO, DK, FI, PL, AT, CH, IE)
- You need impressions-per-country breakdowns for transparency-required campaigns
- You want full targeting parameters (languages, locations, audience filters)

For US/UK/non-EU-only runs, leave it off — you'll get the same search-card data at the basic price.

#### Filter ad formats client-side

LinkedIn doesn't expose a server-side format filter, so every run returns all formats. Use the `format` field in your dataset to filter to just videos, just carousels, etc., after the run completes.

#### Custom date ranges

LinkedIn's Ad Library only retains ~12 months of history. If you set a `startDate` older than 12 months ago, it's automatically clamped to the earliest available date. Both `startDate` and `endDate` are required when `dateOption` is `custom-date-range`.

#### Pagination & overshoot

Results come in pages of 24. The actor stops requesting new pages once your `maxResults` cap is hit, but always keeps the last page intact — so you may get up to 23 extra rows beyond your cap. This avoids losing partial results.

#### Run hygiene

For very large runs (10,000+ ads) split your work across multiple shorter runs by varying the keywords or date window. Shorter runs are easier to monitor and easier to retry if something goes wrong. Each individual keyword or advertiser search is internally capped at roughly 4,800 ads (LinkedIn's pagination depth limit) — if you need more, split a popular keyword into narrower variants (e.g. by country or date range).

### Pricing

**Tiered pay-per-event pricing — you only pay per ad returned.**

- **$0.50 per 1,000 ads** — basic ads (when `fetchDetails` is off, or when detail enrichment data isn't available)
- **$0.90 per 1,000 ads** — ads enriched with detail data (impressions per country and full targeting)

The higher tier triggers automatically when detail enrichment data is available — currently EU ads with public targeting/impression disclosures under the Digital Services Act. You're never charged the higher tier for ads where no extra data was actually delivered.

**No compute charges — you only pay per ad returned.**

#### Example costs

| Ads returned | Basic tier ($0.50 / 1K) | Detail tier ($0.90 / 1K) |
|--------------|-------------------------|---------------------------|
| 100          | $0.05                   | $0.09                     |
| 1,000        | $0.50                   | $0.90                     |
| 10,000       | $5.00                   | $9.00                     |

A typical mixed run (e.g. EU + US ads with `fetchDetails: true`) is billed per-ad: each EU ad fires the detail-tier event, each non-EU ad fires the basic-tier event. The total is the sum.

### Integrations

Export results in JSON, CSV, Excel, XML, or RSS. Connect to 1,500+ apps via:

- **Zapier** / **Make** / **n8n** — Workflow automation
- **Google Sheets** — Direct spreadsheet export
- **Slack** / **Email** — Notifications on new results
- **Webhooks** — Push results to your own endpoints
- **Apify REST API** — Full programmatic access from any backend

### Good to Know

- **Detail enrichment is EU-focused.** `impressionsPerCountry` and `targeting` populate only for ads served in the EU under the Digital Services Act transparency rules. US and other non-EU ads return `null` for these fields even with `fetchDetails: true` — and they're billed at the basic tier in that case.
- **Pagination overshoots, never trims.** Once your `maxResults` cap is reached, no new pages are requested, but the last page is kept whole. You may receive up to 23 extra rows beyond the cap.
- **`dateOption: custom-date-range`** requires both `startDate` and `endDate`, both within the last 12 months. Invalid or older dates are clamped or fall back to `last-30-days`.
- **No server-side format filter.** LinkedIn's Ad Library doesn't expose one. Filter your dataset on the `format` field after the run.

### Legal & Ethical Use

This actor is designed for legitimate market research, competitive intelligence, brand monitoring, and ad creative analysis. The data it collects is from LinkedIn's **public Ad Library** — a transparency portal LinkedIn explicitly publishes for this purpose. Users are responsible for complying with applicable laws and LinkedIn's Terms of Service. Do not use the data for spam, harassment, deceptive comparative advertising, or any illegal purpose.

# Actor input Schema

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

Free-text search terms (e.g. "AI marketing", "crypto"). Each keyword runs its own search and the results are combined. Leave empty to search by advertiser or by direct URLs.

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

LinkedIn company slugs (e.g. "nvidia", "microsoft", "hubspot"). The slug comes from the LinkedIn company URL — `linkedin.com/company/<slug>`. Each advertiser runs its own search. Use the slug exactly as it appears in the URL — display names like "Microsoft Corp" are not deterministic and may return zero results.

## `startUrls` (type: `array`):

Paste full LinkedIn Ad Library search URLs directly. Useful when you've built a search in the LinkedIn UI and want the same results. Bypasses the keyword and advertiser fields above.

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

Restrict results to ads served in these countries. Leave empty to include every country.

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

Time window for when the ad was active. LinkedIn's Ad Library only retains ~12 months of history regardless of the option chosen.

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

Only used when 'Date range' is set to 'Custom date range'. Format YYYY-MM-DD. Must be within the last 12 months.

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

Only used when 'Date range' is set to 'Custom date range'. Format YYYY-MM-DD. Must be within the last 12 months.

## `fetchDetails` (type: `boolean`):

When enabled, opens each ad's detail page to extract impressions-per-country and full targeting (languages, locations). Increases the per-ad price from $0.50 per 1,000 ads to $0.90 per 1,000 ads, and only enriches ads that LinkedIn discloses extra data for (typically EU-served ads). Leave off to keep cost low if you only need search-card data.

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

Cap the total number of ads returned across all queries combined. Set to 0 for unlimited — though each individual search is capped at roughly 4,800 ads (200 pages × 24) by LinkedIn's pagination depth, and the actor stops when it reaches that watchdog limit. Pages contain 24 ads each, so the actor may overshoot your cap by up to 23 to keep the last page intact.

## Actor input object example

```json
{
  "keywords": [
    "marketing automation"
  ],
  "advertisers": [],
  "startUrls": [],
  "countries": [
    "US"
  ],
  "dateOption": "last-30-days",
  "fetchDetails": false,
  "maxResults": 1000
}
```

# Actor output Schema

## `overview` (type: `string`):

Table of scraped ads with advertiser, format, headline, dates, and impressions.

# 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 = {
    "keywords": [
        "marketing automation"
    ],
    "advertisers": [],
    "startUrls": [],
    "countries": [
        "US"
    ],
    "dateOption": "last-30-days",
    "startDate": "",
    "endDate": "",
    "fetchDetails": false,
    "maxResults": 1000
};

// Run the Actor and wait for it to finish
const run = await client.actor("solidcode/linkedin-ads-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 = {
    "keywords": ["marketing automation"],
    "advertisers": [],
    "startUrls": [],
    "countries": ["US"],
    "dateOption": "last-30-days",
    "startDate": "",
    "endDate": "",
    "fetchDetails": False,
    "maxResults": 1000,
}

# Run the Actor and wait for it to finish
run = client.actor("solidcode/linkedin-ads-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "marketing automation"
  ],
  "advertisers": [],
  "startUrls": [],
  "countries": [
    "US"
  ],
  "dateOption": "last-30-days",
  "startDate": "",
  "endDate": "",
  "fetchDetails": false,
  "maxResults": 1000
}' |
apify call solidcode/linkedin-ads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=solidcode/linkedin-ads-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "LinkedIn Ads Scraper",
        "description": "[💰 $0.5 / 1K] Extract ads from LinkedIn's public Ad Library — advertiser, headline, body, format, dates, impressions, CTAs. Search by keyword, advertiser, country, and date range. Optional detail enrichment for impressions-per-country and targeting.",
        "version": "1.0",
        "x-build-id": "b9e0nl0Gg3D9u0IZw"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/solidcode~linkedin-ads-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-solidcode-linkedin-ads-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/solidcode~linkedin-ads-scraper/runs": {
            "post": {
                "operationId": "runs-sync-solidcode-linkedin-ads-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/solidcode~linkedin-ads-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-solidcode-linkedin-ads-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "keywords": {
                        "title": "Keywords",
                        "type": "array",
                        "description": "Free-text search terms (e.g. \"AI marketing\", \"crypto\"). Each keyword runs its own search and the results are combined. Leave empty to search by advertiser or by direct URLs.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "advertisers": {
                        "title": "Advertisers",
                        "type": "array",
                        "description": "LinkedIn company slugs (e.g. \"nvidia\", \"microsoft\", \"hubspot\"). The slug comes from the LinkedIn company URL — `linkedin.com/company/<slug>`. Each advertiser runs its own search. Use the slug exactly as it appears in the URL — display names like \"Microsoft Corp\" are not deterministic and may return zero results.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "Paste full LinkedIn Ad Library search URLs directly. Useful when you've built a search in the LinkedIn UI and want the same results. Bypasses the keyword and advertiser fields above.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "countries": {
                        "title": "Countries",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Restrict results to ads served in these countries. Leave empty to include every country.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "US",
                                "GB",
                                "CA",
                                "AU",
                                "IE",
                                "NZ",
                                "ZA",
                                "IN",
                                "DE",
                                "FR",
                                "ES",
                                "IT",
                                "NL",
                                "BE",
                                "PT",
                                "SE",
                                "NO",
                                "DK",
                                "FI",
                                "PL",
                                "AT",
                                "CH",
                                "BR",
                                "MX",
                                "AR",
                                "CL",
                                "CO",
                                "JP",
                                "KR",
                                "SG",
                                "HK",
                                "TW",
                                "ID",
                                "TH",
                                "VN",
                                "PH",
                                "MY",
                                "AE",
                                "SA",
                                "TR",
                                "IL",
                                "EG"
                            ],
                            "enumTitles": [
                                "United States",
                                "United Kingdom",
                                "Canada",
                                "Australia",
                                "Ireland",
                                "New Zealand",
                                "South Africa",
                                "India",
                                "Germany",
                                "France",
                                "Spain",
                                "Italy",
                                "Netherlands",
                                "Belgium",
                                "Portugal",
                                "Sweden",
                                "Norway",
                                "Denmark",
                                "Finland",
                                "Poland",
                                "Austria",
                                "Switzerland",
                                "Brazil",
                                "Mexico",
                                "Argentina",
                                "Chile",
                                "Colombia",
                                "Japan",
                                "South Korea",
                                "Singapore",
                                "Hong Kong",
                                "Taiwan",
                                "Indonesia",
                                "Thailand",
                                "Vietnam",
                                "Philippines",
                                "Malaysia",
                                "United Arab Emirates",
                                "Saudi Arabia",
                                "Turkey",
                                "Israel",
                                "Egypt"
                            ]
                        },
                        "default": []
                    },
                    "dateOption": {
                        "title": "Date range",
                        "enum": [
                            "last-30-days",
                            "current-month",
                            "current-year",
                            "last-year",
                            "custom-date-range"
                        ],
                        "type": "string",
                        "description": "Time window for when the ad was active. LinkedIn's Ad Library only retains ~12 months of history regardless of the option chosen.",
                        "default": "last-30-days"
                    },
                    "startDate": {
                        "title": "Custom start date",
                        "type": "string",
                        "description": "Only used when 'Date range' is set to 'Custom date range'. Format YYYY-MM-DD. Must be within the last 12 months."
                    },
                    "endDate": {
                        "title": "Custom end date",
                        "type": "string",
                        "description": "Only used when 'Date range' is set to 'Custom date range'. Format YYYY-MM-DD. Must be within the last 12 months."
                    },
                    "fetchDetails": {
                        "title": "Fetch full ad details (impressions per country + targeting)",
                        "type": "boolean",
                        "description": "When enabled, opens each ad's detail page to extract impressions-per-country and full targeting (languages, locations). Increases the per-ad price from $0.50 per 1,000 ads to $0.90 per 1,000 ads, and only enriches ads that LinkedIn discloses extra data for (typically EU-served ads). Leave off to keep cost low if you only need search-card data.",
                        "default": false
                    },
                    "maxResults": {
                        "title": "Max results",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Cap the total number of ads returned across all queries combined. Set to 0 for unlimited — though each individual search is capped at roughly 4,800 ads (200 pages × 24) by LinkedIn's pagination depth, and the actor stops when it reaches that watchdog limit. Pages contain 24 ads each, so the actor may overshoot your cap by up to 23 to keep the last page intact.",
                        "default": 1000
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
