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

Extract ads from LinkedIn Ad Library — no login needed. Get headlines, body text, CTA labels + URLs, media images, ad format, and funding entity. 50% cheaper than competitors at $0.001/ad.

- **URL**: https://apify.com/automation-lab/linkedin-ad-library-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Business, Marketing
- **Stats:** 5 total users, 2 monthly users, 100.0% runs succeeded, NaN 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.
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 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 Ad Library Scraper

> Extract ads, creatives, headlines, media URLs, CTAs, and funding entities from the LinkedIn Ad Library — no login, no API key, no browser required.

### What does it do?

LinkedIn Ad Library Scraper pulls publicly available ad data from [LinkedIn's Ad Transparency tool](https://www.linkedin.com/ad-library/search). For any company, brand, or keyword you search, it returns up to 24 ads per query including:

- 📝 **Ad copy** — full headline and body text
- 🖼 **Creative URL** — direct link to the ad image or video
- 🔗 **Call-to-action** — CTA label and destination URL
- 🏢 **Advertiser details** — company name and LinkedIn URL
- 💰 **Funding entity** — who paid for the ad (useful for agency clients)
- 📅 **Format** — Single Image, Video, Carousel, Text, Dynamic, Follow Company

The scraper uses direct HTTP requests with Cheerio HTML parsing — no Playwright, no headless browser. It's fast, cheap, and runs at 256 MB memory.

---

### Who is it for?

#### 🏆 Competitive Intelligence Teams
Monitor which ads your direct competitors are running. See their messaging, offers, and visuals without needing a LinkedIn account or paying for premium tools.

#### 📣 Performance Marketers & Creative Teams
Analyze high-performing ad copy patterns across your industry. Identify CTA formulas, headline structures, and visual styles that resonate with B2B buyers on LinkedIn.

#### 🕵️ Market Researchers & Consultants
Audit a client's advertising presence or benchmark an industry. Pull ads from multiple company URLs in a single run.

#### 🤖 Marketing Automation Engineers
Feed ad data into content pipelines, CRM systems, or AI workflows using the Apify API or native n8n/Make/Zapier integrations.

---

### Why use this scraper?

- ✅ **No login required** — LinkedIn Ad Library is a public transparency tool
- ✅ **No API key needed** — works out of the box
- ✅ **50% cheaper than competitors** — $0.001/ad at BRONZE vs $0.002 elsewhere
- ✅ **Full creative data** — headline, body, CTA label + URL, media image URL, funding entity
- ✅ **Multiple advertisers** — paste a list of LinkedIn company URLs to batch multiple brands
- ✅ **Filters** — date range, ad format, country, sort order
- ✅ **Lightweight** — HTTP-only, 256 MB memory, no browser overhead

---

### Scraped data fields

| Field | Description | Example |
|-------|-------------|---------|
| `adId` | Unique LinkedIn ad identifier | `1200494683` |
| `advertiserName` | Company running the ad | `Salesforce` |
| `advertiserLinkedInUrl` | LinkedIn company page URL | `https://www.linkedin.com/company/salesforce` |
| `advertiserCompanyId` | LinkedIn internal company ID | `1281394` |
| `adFormat` | Ad format type | `Single Image Ad` |
| `headline` | Ad headline text | `Unlock AI productivity today` |
| `bodyText` | Full ad copy/body text | `Join 150,000+ companies using...` |
| `ctaLabel` | Call-to-action button label | `Learn more` |
| `ctaUrl` | CTA destination URL | `https://www.salesforce.com/...` |
| `mediaUrl` | Direct URL to ad image or video thumbnail | `https://media.licdn.com/...` |
| `fundingEntityName` | Who paid for the ad (advertiser or agency) | `Iprospect.com Inc.` |
| `detailUrl` | Direct link to ad detail page | `https://www.linkedin.com/ad-library/detail/...` |
| `scrapedAt` | ISO timestamp when the ad was scraped | `2026-03-31T11:32:52Z` |

---

### How much does it cost to scrape LinkedIn ads?

Pricing is **pay-per-result** — you only pay for ads successfully extracted.

| Tier | Start fee | Per ad | 24 ads total |
|------|-----------|--------|-------------|
| FREE | $0.005 | $0.00115 | ~$0.033 |
| BRONZE | $0.005 | $0.001 | ~$0.029 |
| SILVER | $0.005 | $0.00078 | ~$0.024 |
| GOLD | $0.005 | $0.0006 | ~$0.019 |
| PLATINUM | $0.005 | $0.0004 | ~$0.015 |
| DIAMOND | $0.005 | $0.00028 | ~$0.012 |

> 💡 **Example**: Scraping 24 ads from Salesforce costs ~$0.033 on the FREE tier, or ~$0.029 on BRONZE. That's 50% cheaper than comparable scrapers on the Store.

**Limitation**: LinkedIn's Ad Library returns up to 24 ads per search query via its public HTML. To get ads from multiple companies, add multiple URLs to the **Advertiser URLs** field — each query returns up to 24 ads independently.

---

### How to use

#### Step 1 — Choose your search mode

**Option A: Search by keyword or company name**
Enter a company name like `Nike` or `HubSpot` in the **Search Query** field.

**Option B: Target specific advertisers**
Paste LinkedIn company URLs into **Advertiser URLs** (one per line):
````

https://www.linkedin.com/company/salesforce
https://www.linkedin.com/company/hubspot
https://www.linkedin.com/company/microsoft

````
This runs a separate search per URL and returns up to 24 ads each.

#### Step 2 — Set filters (optional)

- **Date Range**: Choose from past 24h, past week, past month, past year, or all-time
- **Ad Format**: Filter to image, video, carousel, text, or dynamic ads
- **Country Filter**: Enter a 2-letter ISO code (US, GB, DE, FR) to see country-specific ads
- **Sort Order**: Most recent (default) or most clicks

#### Step 3 — Run and collect data

Click **Start** and data will appear in the **Dataset** tab as it's extracted. For bulk exports, use the **Export** button (CSV, XLSX, JSON, JSONL).

---

### Input reference

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `searchQuery` | string | No* | — | Company name or keyword to search |
| `advertiserUrls` | array | No* | `[]` | LinkedIn company page URLs |
| `maxAds` | integer | No | `50` | Max ads to extract (practical max ~24 per query) |
| `dateRange` | string | No | `past-month` | `all-time`, `past-day`, `past-week`, `past-month`, `past-year` |
| `adFormat` | string | No | `all` | `all`, `SPONSORED_UPDATES`, `TEXT_ADS`, `DYNAMIC_ADS`, `CAROUSEL` |
| `countryCode` | string | No | — | 2-letter ISO country code (US, GB, DE, etc.) |
| `sortBy` | string | No | `RECENT` | `RECENT` or `MOST_CLICKS` |
| `maxRequestRetries` | integer | No | `3` | Retry attempts per request |

\* Either `searchQuery` or at least one `advertiserUrls` entry is required.

---

### Output example

```json
{
  "adId": "1200494683",
  "advertiserName": "Salesforce",
  "advertiserLinkedInUrl": "https://www.linkedin.com/company/1281394",
  "advertiserCompanyId": "1281394",
  "adFormat": "Single Image Ad",
  "headline": "Agentforce World Tour São Paulo",
  "bodyText": "Gostaríamos de te convidar para o maior evento sobre IA Agêntica da América Latina!",
  "ctaLabel": "Inscreva-se",
  "ctaUrl": "https://www.salesforce.com/br/events/agentforce-world-tour/",
  "mediaUrl": "https://media.licdn.com/dms/image/v2/D4D10AQHWOhThVHEqXA/image-shrink_1280/...",
  "fundingEntityName": "Iprospect.com Inc.",
  "detailUrl": "https://www.linkedin.com/ad-library/detail/1200494683",
  "scrapedAt": "2026-03-31T11:32:52.764Z"
}
````

***

### Tips for best results

#### Getting more ads from one advertiser

LinkedIn's public HTML returns up to 24 ads per query. Use the **date range** and **format** filters to get different slices:

- Run once with `past-month` (most recent active ads)
- Run again with `past-year` for historical ads
- Run again with `MOST_CLICKS` sort to find their best performers

#### Batch multiple competitors

Add all competitor company URLs to the **Advertiser URLs** list. Each URL runs as a separate query, so 10 URLs = up to 240 ads.

#### Exporting to Google Sheets

Use Apify's [Google Sheets integration](https://apify.com/apify/google-sheets) to automatically push scraped ads into a spreadsheet for team sharing.

#### Filtering by country

Use `countryCode` to see what ads a company runs specifically in a market (e.g., `US` for US-only campaigns).

***

### Integrations

#### n8n workflow: Competitor ad monitoring

1. Schedule this scraper weekly via n8n HTTP node
2. Push results to a Notion database or Airtable
3. Trigger Slack notification when new ads appear from key competitors

#### Make (Integromat): Creative analysis pipeline

1. Run scraper → collect `mediaUrl` + `headline` + `bodyText`
2. Send to OpenAI GPT-4 for categorization (promotional/brand/event/product)
3. Save to Google Sheets with category tags

#### Zapier: CRM enrichment

1. Trigger on new Salesforce competitor account
2. Run this scraper on their LinkedIn URL
3. Create a "competitor ad" record in HubSpot with ad copy and creative URL

***

### API usage

Run this scraper programmatically using the Apify API:

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('automation-lab/linkedin-ad-library-scraper').call({
  searchQuery: 'HubSpot',
  maxAds: 24,
  dateRange: 'past-month',
  sortBy: 'MOST_CLICKS',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Scraped ${items.length} ads`);
items.forEach(ad => {
  console.log(`${ad.advertiserName}: ${ad.headline}`);
});
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run = client.actor("automation-lab/linkedin-ad-library-scraper").call(
    run_input={
        "advertiserUrls": [
            "https://www.linkedin.com/company/salesforce",
            "https://www.linkedin.com/company/hubspot",
        ],
        "maxAds": 50,
        "dateRange": "past-month",
        "sortBy": "MOST_CLICKS",
    }
)

dataset = client.dataset(run["defaultDatasetId"])
for item in dataset.iterate_items():
    print(f"{item['advertiserName']}: {item['headline']}")
```

#### cURL

```bash
curl -s -X POST \
  "https://api.apify.com/v2/acts/automation-lab~linkedin-ad-library-scraper/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "searchQuery": "Salesforce",
    "maxAds": 24,
    "dateRange": "past-month"
  }' | jq '.data.id'
```

***

### Use with Claude (MCP)

Connect this scraper to Claude Desktop or Claude Code via the [Apify MCP server](https://apify.com/apify/actors-mcp-server). This lets Claude run the scraper and analyze results conversationally.

#### Setup

Add this MCP server URL to your Claude Desktop config (`claude_desktop_config.json`) or Claude Code settings:

```
https://mcp.apify.com?tools=automation-lab/linkedin-ad-library-scraper
```

Or use the full Apify MCP Server actor for more control:

```json
{
  "mcpServers": {
    "apify": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/mcp-apify", "--actors", "automation-lab/linkedin-ad-library-scraper"]
    }
  }
}
```

#### Example prompts

> "Scrape the last 24 ads from Salesforce on LinkedIn and summarize their key messaging themes."

> "Get LinkedIn ads from HubSpot from the past month sorted by most clicks, then identify the top 3 CTA patterns they use."

> "Pull ads from these 5 companies: \[URLs] and compare their headline styles."

> "Monitor Stripe's LinkedIn ads weekly and alert me when they launch new campaigns."

#### What Claude can do with the results

- **Competitive analysis** — Compare messaging themes across multiple advertisers
- **Creative briefs** — Generate ad copy ideas based on competitor patterns
- **Trend reports** — Identify shifts in ad format, CTA language, or visual styles over time
- **Data enrichment** — Cross-reference ad data with other Apify scrapers for richer insights

***

### Legality

LinkedIn's Ad Library is a **public transparency tool** required by regulations for advertising accountability. Accessing publicly available data for research, competitive intelligence, and analysis is widely accepted.

This scraper:

- Does NOT require a LinkedIn account or login
- Does NOT bypass any authentication or paywalls
- Only accesses the public `/ad-library/` URL space
- Complies with LinkedIn's transparency program intent

Always use scraped data responsibly and in accordance with your jurisdiction's data protection laws.

***

### FAQ

#### How many ads can I get per run?

LinkedIn's public HTML returns up to 24 ads per search query. To get more ads, provide multiple advertiser URLs — each URL is a separate query returning up to 24 ads.

#### Why don't I see impressions or click counts?

LinkedIn's public Ad Library does not expose impression counts or click metrics via its HTML interface. Fields like `totalImpressions` are reserved for future API integration if LinkedIn opens that data.

#### I searched for a company and got 0 results — why?

This can happen if:

- The company name is too generic (try their company URL instead)
- The company hasn't run ads recently in the selected date range
- LinkedIn is temporarily rate-limiting requests (try again in a few minutes)

#### How is this different from silva95's LinkedIn Ad Library scraper?

Our scraper: always returns full details (headline, body, CTA, media, funding entity) at $0.001/ad. silva95 charges $0.002 for basic fields or $0.004 for detailed — 2-4x more expensive for the same data.

#### Can I scrape video ads?

Yes. Video ads are detected and their thumbnail `mediaUrl` is extracted. Direct video file URLs are not currently available from the public HTML.

#### Does this require a proxy?

Yes, the scraper uses Apify proxy automatically. You don't need to configure anything.

***

### Related scrapers

- [LinkedIn Jobs Enrichment](https://apify.com/automation-lab/linkedin-jobs-enrichment) — Enrich job listings with full details
- [LinkedIn Company Scraper](https://apify.com/automation-lab/linkedin-company-scraper) — Extract company profiles
- [Facebook Ads Library Scraper](https://apify.com/automation-lab/facebook-ads-library) — Scrape Meta Ad Library ads

***

*Built by [automation-lab](https://apify.com/automation-lab) — professional Apify actors for data teams.*

# Actor input Schema

## `searchQuery` (type: `string`):

Enter a company name, brand, or keywords to search the LinkedIn Ad Library. Example: "Nike", "Salesforce", "cloud software".

## `advertiserUrls` (type: `array`):

Paste LinkedIn company page URLs to scrape ads from specific advertisers directly (e.g. https://www.linkedin.com/company/salesforce). Takes priority over Search Query when provided.

## `maxAds` (type: `integer`):

Maximum number of ads to extract per run. Keep low for quick tests, increase for bulk research.

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

Filter ads by the time period they ran. 'Past month' is the most common for competitive research.

## `adFormat` (type: `string`):

Filter by ad format. Leave as 'All formats' to scrape all types including images, videos, carousels, and text ads.

## `countryCode` (type: `string`):

Filter ads by country where shown. Use 2-letter ISO code (US, GB, DE, FR, AU, CA, IN, etc.). Leave empty to get ads from all countries.

## `sortBy` (type: `string`):

Sort ads by recency or engagement. 'Most recent' gives the latest ads; 'Most clicks' surfaces highest-engagement ads.

## `maxRequestRetries` (type: `integer`):

Number of times to retry failed requests before skipping. Increase if you see many 'request failed' warnings.

## Actor input object example

```json
{
  "searchQuery": "Salesforce",
  "advertiserUrls": [],
  "maxAds": 25,
  "dateRange": "past-month",
  "adFormat": "all",
  "countryCode": "",
  "sortBy": "RECENT",
  "maxRequestRetries": 3
}
```

# Actor output Schema

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

No description

# 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 = {
    "searchQuery": "Salesforce",
    "advertiserUrls": [],
    "maxAds": 25,
    "dateRange": "past-month",
    "adFormat": "all",
    "countryCode": "",
    "sortBy": "RECENT",
    "maxRequestRetries": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/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 = {
    "searchQuery": "Salesforce",
    "advertiserUrls": [],
    "maxAds": 25,
    "dateRange": "past-month",
    "adFormat": "all",
    "countryCode": "",
    "sortBy": "RECENT",
    "maxRequestRetries": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/linkedin-ad-library-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 '{
  "searchQuery": "Salesforce",
  "advertiserUrls": [],
  "maxAds": 25,
  "dateRange": "past-month",
  "adFormat": "all",
  "countryCode": "",
  "sortBy": "RECENT",
  "maxRequestRetries": 3
}' |
apify call automation-lab/linkedin-ad-library-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "LinkedIn Ad Library Scraper",
        "description": "Extract ads from LinkedIn Ad Library — no login needed. Get headlines, body text, CTA labels + URLs, media images, ad format, and funding entity. 50% cheaper than competitors at $0.001/ad.",
        "version": "0.1",
        "x-build-id": "8guXLQS8z1Zmho8fv"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/automation-lab~linkedin-ad-library-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-automation-lab-linkedin-ad-library-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/automation-lab~linkedin-ad-library-scraper/runs": {
            "post": {
                "operationId": "runs-sync-automation-lab-linkedin-ad-library-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/automation-lab~linkedin-ad-library-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-automation-lab-linkedin-ad-library-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": {
                    "searchQuery": {
                        "title": "🔍 Search Query",
                        "type": "string",
                        "description": "Enter a company name, brand, or keywords to search the LinkedIn Ad Library. Example: \"Nike\", \"Salesforce\", \"cloud software\"."
                    },
                    "advertiserUrls": {
                        "title": "🏢 Advertiser URLs",
                        "type": "array",
                        "description": "Paste LinkedIn company page URLs to scrape ads from specific advertisers directly (e.g. https://www.linkedin.com/company/salesforce). Takes priority over Search Query when provided.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxAds": {
                        "title": "Max Ads",
                        "minimum": 1,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Maximum number of ads to extract per run. Keep low for quick tests, increase for bulk research.",
                        "default": 50
                    },
                    "dateRange": {
                        "title": "📅 Date Range",
                        "enum": [
                            "all-time",
                            "past-day",
                            "past-week",
                            "past-month",
                            "past-year"
                        ],
                        "type": "string",
                        "description": "Filter ads by the time period they ran. 'Past month' is the most common for competitive research.",
                        "default": "past-month"
                    },
                    "adFormat": {
                        "title": "🎨 Ad Format",
                        "enum": [
                            "all",
                            "SPONSORED_UPDATES",
                            "TEXT_ADS",
                            "DYNAMIC_ADS",
                            "CAROUSEL"
                        ],
                        "type": "string",
                        "description": "Filter by ad format. Leave as 'All formats' to scrape all types including images, videos, carousels, and text ads.",
                        "default": "all"
                    },
                    "countryCode": {
                        "title": "🌍 Country Filter",
                        "type": "string",
                        "description": "Filter ads by country where shown. Use 2-letter ISO code (US, GB, DE, FR, AU, CA, IN, etc.). Leave empty to get ads from all countries.",
                        "default": ""
                    },
                    "sortBy": {
                        "title": "Sort Order",
                        "enum": [
                            "RECENT",
                            "MOST_CLICKS"
                        ],
                        "type": "string",
                        "description": "Sort ads by recency or engagement. 'Most recent' gives the latest ads; 'Most clicks' surfaces highest-engagement ads.",
                        "default": "RECENT"
                    },
                    "maxRequestRetries": {
                        "title": "Max Request Retries",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Number of times to retry failed requests before skipping. Increase if you see many 'request failed' warnings.",
                        "default": 3
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
