# Meta Ad Library Scraper - Facebook Ads, Days Running & Changes (`webdatalabs/meta-ad-library-scraper`) Actor

Scrape Meta Ad Library by keyword and get what other scrapers skip: exact days each ad has been running, AFINN sentiment on the copy, advertiser Page likes, per-carousel-card creatives, and a new-vs-changed flag across scheduled runs. Facebook, Instagram, Messenger, Threads. 249 countries.

- **URL**: https://apify.com/webdatalabs/meta-ad-library-scraper.md
- **Developed by:** [WebDataLabs](https://apify.com/webdatalabs) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 622 total users, 57 monthly users, 79.4% runs succeeded, 17 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $17.00 / 1,000 ad scrapeds

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

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Meta Ad Library Scraper - Facebook & Instagram Ads, Competitor Intelligence

Extract competitor ads from Meta's Ad Library (Facebook, Instagram, Messenger, Audience Network). Get ad copy, creatives, targeting data, sentiment analysis, and track changes over time.

**Pricing: from $0.017 per ad** | No coding required | Export to CSV, JSON, Excel

### What This Scraper Does

The Meta Ad Library Scraper extracts publicly available advertising data from Meta's transparency database. Unlike unreliable DOM scrapers, this tool uses **GraphQL interception** to capture the actual API responses - the same data Meta displays in their interface.

**Platforms covered:**

- Facebook
- Instagram
- Messenger
- Audience Network

### Quick Start

#### 1. Configure Your Search

```json
{
  "searchQueries": ["running shoes", "fitness app", "gym membership"],
  "country": "US",
  "activeStatus": "active",
  "adType": "all",
  "mediaType": "all",
  "maxAds": 20
}
```

#### 2. Run the Scraper

Click **Start** in Apify Console, or use the API:

```bash
apify call webdatalabs/meta-ad-library-scraper -i '{
  "searchQueries": ["running shoes", "fitness app"],
  "country": "US",
  "maxAds": 20
}'
```

#### 3. Export Your Data

Download results in CSV, JSON, or Excel format. Integrate with n8n, Zapier, Make, or any automation tool.

***

### What You Get

Each ad record includes:

| Field | Description |
|-------|-------------|
| `adArchiveId` | Unique Meta ad identifier |
| `pageName` | Advertiser name |
| `pageId` | Advertiser's Facebook Page ID |
| `pageUrl` | Link to advertiser's Page |
| `pageLikeCount` | Page follower count |
| `pageCategory` | Business category |
| `isActive` | Whether ad is currently running |
| `startDate` | When ad started running |
| `endDate` | When ad stopped (if inactive) |
| `runDurationDays` | How long the ad has been running |
| `platforms` | Where ad runs (Facebook, Instagram, etc.) |
| `adCopy` | Main ad text |
| `headline` | Ad headline |
| `ctaType` | Call-to-action type (LEARN\_MORE, SHOP\_NOW, etc.) |
| `ctaText` | CTA button text |
| `landingUrl` | Destination URL |
| `imageUrls` | Array of image URLs |
| `videoUrls` | Array of video URLs |
| `cards` | Carousel card data (for multi-image ads) |
| `sentimentScore` | NLP sentiment score (-5 to +5) |
| `sentimentLabel` | positive / negative / neutral |
| `impressionsText` | Impression range (EU transparency) |
| `categories` | Ad categories (Housing, Political, etc.) |
| `scrapedAt` | Timestamp of data collection |

#### Example Output

```json
{
  "adArchiveId": "1908832149745499",
  "pageName": "Nike",
  "pageId": "15087023444",
  "pageUrl": "https://www.facebook.com/15087023444",
  "pageLikeCount": 36254891,
  "pageCategory": "Clothing Brand",
  "isActive": true,
  "startDate": "2024-01-15T00:00:00.000Z",
  "endDate": null,
  "runDurationDays": 45,
  "platforms": ["FACEBOOK", "INSTAGRAM", "AUDIENCE_NETWORK"],
  "platformCount": 3,
  "adCopy": "Just Do It. New Pegasus 41 - engineered for your fastest runs yet.",
  "headline": "Nike Pegasus 41",
  "ctaType": "SHOP_NOW",
  "ctaText": "Shop Now",
  "landingUrl": "https://www.nike.com/running/pegasus",
  "imageUrls": [
    "https://scontent.xx.fbcdn.net/v/..."
  ],
  "videoUrls": [],
  "cards": [],
  "sentimentScore": 2.5,
  "sentimentComparative": 0.25,
  "sentimentLabel": "positive",
  "impressionsText": null,
  "categories": [],
  "firstSeenAt": "2024-01-20T10:30:00.000Z",
  "lastSeenAt": "2024-03-01T14:22:00.000Z",
  "changeDetected": false,
  "scrapedAt": "2024-03-01T14:22:00.000Z",
  "searchQuery": "running shoes",
  "country": "US"
}
```

***

### Use Cases

#### 1. Competitive Intelligence

Monitor what ads your competitors are running:

- Track their messaging and positioning
- See which platforms they target
- Analyze their creative strategies
- Identify new product launches

#### 2. Ad Creative Inspiration

Research successful ad formats in your industry:

- Find high-performing ad copy patterns
- Discover trending visual styles
- Analyze CTA strategies
- Study carousel vs. single image performance

#### 3. Market Research

Understand advertising trends in any market:

- Compare ad activity across countries
- Track seasonal advertising patterns
- Analyze industry spending trends
- Monitor political/issue ads in specific regions

#### 4. Brand Protection

Monitor unauthorized use of your brand:

- Find ads mentioning your brand
- Detect counterfeit product ads
- Track competitor brand comparisons
- Identify affiliate compliance issues

#### 5. Agency Reporting

Create comprehensive competitor reports:

- Scheduled daily/weekly data collection
- Historical trend analysis
- Sentiment analysis on competitor messaging
- Export-ready data for client presentations

***

### Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchQueries` | string\[] | *required* | Keywords to search. Add multiple entries to scrape several queries in one run. Legacy `searchQuery` (single string) still supported for backward compatibility. |
| `country` | select | `DE` | Country to search, picked from a dropdown of all 249 ISO 3166-1 codes. Free text is no longer accepted - `"India"` is rejected before the run starts, `"IN"` is correct. |
| `activeStatus` | enum | `active` | Filter: `active`, `inactive`, or `all` |
| `adType` | enum | `all` | Filter: `all`, `political_and_issue_ads`, `housing`, `employment`, `credit` |
| `mediaType` | enum | `all` | Filter: `all`, `image`, `video`, `meme` |
| `maxAds` | number | `20` | Maximum ads per query (1-10,000). Total ads = maxAds × number of queries. |
| `sortMode` | enum | `newest` | `newest` = recently created ads first (fresh leads each run). `most_impressions` = highest-reach ads first (competitive research); this is also Meta's own default order. |
| `analyzeSentiment` | boolean | `true` | Enable AFINN-165 sentiment analysis |
| `trackChanges` | boolean | `true` | Track changes across scheduled runs |
| `useProxies` | boolean | `true` | Use residential proxies (recommended) |
| `proxyGroups` | array | `["RESIDENTIAL"]` | Apify proxy groups to use |

#### Country Codes

Pick the country from the dropdown in the Console. Over the API, pass the **two-letter ISO 3166-1 alpha-2 code**, not the country name:

`US` (United States), `IN` (India), `SA` (Saudi Arabia), `DE` (Germany), `GB` (United Kingdom), `FR` (France), `CA` (Canada), `AU` (Australia), `ES` (Spain), `IT` (Italy), `NL` (Netherlands), `BR` (Brazil)

[Full list of ISO 3166-1 alpha-2 codes](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)

> If you have a saved task or schedule created before July 2026 that stores a country **name** (e.g. `India`), open it once and re-pick the country from the dropdown.

***

### How to read the result of a run

Every run writes a `OUTPUT` record to the key-value store and prints a per-query summary, so a zero is never ambiguous:

| Per-query status | Meaning | What to do |
|------------------|---------|------------|
| `delivered` | Ads found and written to the dataset | Nothing |
| `no-ads-found` | Meta's Ad Library genuinely has no ads for that term in that country | Try the advertiser's native-language spelling (an Arabic brand usually only matches its Arabic name), a shorter term, or Ad Status `All ads` |
| `blocked` | We could not reach Meta (block, rate limit, proxy failure). **Not** an empty result | Re-run; make sure residential proxies are enabled |
| `partial-budget` / `skipped-budget` | The run's cost limit was reached, so the remaining ads were not scraped | Raise **Max total charge** in the run options |
| `partial-timeout` / `partial-interrupted` | Stopped early on the run time limit or a dropped connection | Re-run, or raise the run timeout |
| `partial-aborted` | The run was stopped while this search was still running | See "If a run is stopped early" below |
| `not-run` | The run was stopped before this search started | See "If a run is stopped early" below |

The number printed as **"Ads delivered to the dataset"** is the number of rows that actually landed - it can never be higher than the dataset item count.

#### If a run is stopped early

A run can be stopped before it finishes - most often because your Apify account reached its monthly
usage limit, or because someone stopped it. When that happens the ads already collected are yours
and stay in the dataset; the searches that never ran are **not** silently dropped.

The `OUTPUT` record tells you exactly where the run got to:

| Field | What it tells you |
|-------|-------------------|
| `interrupted` | `true` if the run was stopped rather than finishing on its own |
| `queriesNotRun` | The searches that never ran |
| `queryInProgress` | The search that was mid-flight when the run stopped |
| `rerunInput` | **A ready-to-paste input containing only the missing searches** |
| `isFinal` | `false` means this is a live progress snapshot, not the closing summary |

**To get the rest:** copy `rerunInput` into a new run. It contains only what is still missing, so you
are not charged again for ads you already have.

**Or press Resurrect** on the stopped run: it picks up where it left off, skipping every search that
already completed. Searches that were only half-finished are retried in full, so a small number of
ads from that one search can appear twice.

#### Run cost limit

This actor bills per delivered ad. If a run hits its **Max total charge**, it stops immediately, tells you how many ads it delivered versus how many you asked for, and lists the queries it never got to. You are never charged for ads that were not delivered.

#### Memory

**1 GB is the right setting** and is the actor default. The fast HTTP path peaks around 160 MB; more memory just costs more. The browser fallback (used only when Meta blocks the HTTP path) needs at least 1 GB - below that the actor refuses to launch it and says so rather than being killed by the container.

***

### How to Use

#### Via Apify Console

1. Go to [Meta Ad Library Scraper](https://apify.com/webdatalabs/meta-ad-library-scraper)
2. Fill in the input form
3. Click **Start**
4. Download results when complete

#### Via API

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

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

const run = await client.actor('webdatalabs/meta-ad-library-scraper').call({
  searchQueries: ['fitness app', 'gym membership', 'protein powder'],
  country: 'US',
  activeStatus: 'active',
  maxAds: 50,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Via CLI

```bash
apify call webdatalabs/meta-ad-library-scraper \
  -i '{"searchQueries":["coffee shop","cafe","espresso"],"country":"GB","maxAds":20}'
```

#### Scheduled Runs

Set up recurring scrapes for continuous monitoring:

1. Go to **Schedules** in Apify Console
2. Create new schedule (daily, weekly, etc.)
3. Enable **Change Tracking** to identify new/modified ads
4. Connect webhook for real-time notifications

***

### Features

#### GraphQL Interception

Unlike DOM scrapers that break when Facebook changes their UI, this scraper intercepts the actual GraphQL API responses. This provides:

- **Reliability**: Captures the same data Facebook uses internally
- **Completeness**: Gets all fields, not just visible ones
- **Speed**: Direct data access without DOM parsing

#### Sentiment Analysis

Built-in AFINN-165 NLP analysis on ad copy:

- **sentimentScore**: Raw score (-5 to +5 scale)
- **sentimentComparative**: Normalized score (per word)
- **sentimentLabel**: Simple classification (positive/negative/neutral)

Useful for understanding competitor messaging tone and tracking sentiment trends.

#### Change Tracking

When enabled, the scraper maintains state across runs:

- Identifies **new ads** that weren't seen before
- Detects **changes** to existing ads (copy, status, etc.)
- Stores **firstSeenAt** and **lastSeenAt** timestamps

Perfect for scheduled monitoring and trend analysis.

#### Proxy Support

This scraper uses Apify's proxy infrastructure for reliable access to Meta's Ad Library:

- Uses Apify's residential proxy pool by default
- Distributes requests across IPs for reliability
- Runs in non-headless mode for maximum compatibility

***

### Technical Details

#### How It Works

1. **URL Construction**: Builds Ad Library URL with your search parameters
2. **Browser Launch**: Opens Chrome for JavaScript-rendered page extraction
3. **GraphQL Interception**: Captures API responses as you scroll
4. **Data Transformation**: Normalizes raw GraphQL to clean output format
5. **Sentiment Analysis**: Runs AFINN-165 on ad copy (if enabled)
6. **State Management**: Tracks seen ads for change detection
7. **Dataset Storage**: Saves each ad with pay-per-event billing

#### Rate Limits

- Scroll-based pagination (no direct API calls)
- Built-in delays between scrolls
- Residential proxies provide geo-distributed access for reliability

#### Limitations

- **Spend/Impressions**: Only available for EU transparency ads (political, housing in some regions). `impressionsText`, `impressionsIndex` and `spendText` are `null` for everything else - we never substitute a placeholder value.
- **Historical data**: Only current ads visible (Meta doesn't expose a historical archive)
- **Search matches ad text, not brands**: Meta matches the words in the ad itself. A brand that advertises in Arabic will not be found by its Latin transliteration - search the native-language spelling.
- **Rate limits**: Meta throttles per IP. The actor detects a throttle and reports it as `blocked`; it never reports a throttle as "0 ads found".

***

### Pricing

**From $0.017 per ad** (pay-per-event billing; $0.02 on the free plan, lower rates on paid Apify plans)

| Ads | Cost (from) |
|-----|-------------|
| 100 | $1.70 |
| 500 | $8.50 |
| 1,000 | $17.00 |
| 5,000 | $85.00 |

Plus Apify platform costs (compute + residential proxy bandwidth).

**Residential proxy usage**: ~50-100 MB per 1,000 ads

***

### Integrations

#### n8n

Use the **Apify Trigger** node to start scrapes and **Apify Dataset** node to retrieve results. Connect to Google Sheets, Slack, or any other n8n node.

#### Zapier

1. Add **Apify** integration
2. Trigger: "New Dataset Item"
3. Connect to your destination (Sheets, Airtable, Slack, etc.)

#### Make (Integromat)

Use the Apify modules to:

- Schedule recurring scrapes
- Process new ads automatically
- Push to CRM or database

#### Webhooks

Configure webhooks in Apify to receive notifications when:

- Scrape completes
- New ads detected (with change tracking)

***

### FAQ

#### Is this legal?

Yes. Meta Ad Library is a public transparency database. All data scraped is publicly accessible without login. This scraper accesses the same data any user can see by visiting ads.facebook.com.

#### Why do I need residential proxies?

Residential proxies provide geo-distributed IPs that improve reliability and access consistency when extracting from Meta's Ad Library.

#### How often can I run this?

As often as needed. For competitive monitoring, daily or weekly schedules work well. Enable **Change Tracking** to only flag new/modified ads.

#### What if I hit rate limits?

The scraper automatically handles rate limiting through scroll delays and proxy rotation. Very large scrapes (10,000+ ads) may run slower but will complete.

#### Can I scrape without an Apify account?

No, this runs on the Apify platform. You need an account (free tier available) and API token for automation.

***

### Related Scrapers

Looking for other data sources? Check out these scrapers on Apify Store:

- **Social Media**: TikTok, Reddit, Discord scrapers
- **E-commerce**: Shopify, Amazon, eBay scrapers
- **Business Data**: Google Maps, LinkedIn scrapers

Browse all scrapers at [apify.com/store](https://apify.com/store)

***

### Related actors

- [Meta Threads Scraper](https://apify.com/webdatalabs/meta-threads-scraper) — public Threads posts, replies, profiles and keyword search, no login
- [Facebook Ad Scraper with AI Analysis](https://apify.com/webdatalabs/facebook-ad-intelligence-pro) — ad creative scored and summarised
- [Reddit Scraper Pro](https://apify.com/webdatalabs/reddit-scraper-pro) — posts and full comment threads

### Support

Need help? Have questions?

- Open an issue in the [Apify Console](https://console.apify.com/actors) on this actor's page
- Check the [Apify Documentation](https://docs.apify.com) for platform help

***

***

### Need this data as a managed feed?

If you would rather receive this data on a schedule than run the Actor yourself, we can build and operate the feed: the fields you specify, the cadence you set, delivered to a dataset, S3, a webhook, or your database. Every scheduled run is checked against an agreed shape rather than assumed to be fine, missing values are reported as null instead of filled with placeholders, and repairing the collector when the source changes is covered by the monthly rate. Priced as a one-time setup fee plus a monthly rate, scoped in writing before anything is built.

**Contact:** support@webdatalabs.net

### Leave a review

Is this actor saving you time? A quick review on the Store helps other people find it — and tells us which fields to add next. **[Rate this actor →](https://apify.com/webdatalabs/meta-ad-library-scraper)**

### Legal Disclaimer

This actor is provided for legitimate business purposes such as competitive analysis, market research, and brand monitoring using publicly available data from Meta's Ad Library transparency database.

Users are solely responsible for ensuring compliance with:

- Applicable laws and regulations (GDPR, CCPA, etc.)
- Meta's Terms of Service
- Apify's Terms of Service

The developer disclaims liability for any misuse. By using this actor, users agree to indemnify the developer against any claims arising from their use of the scraped data.

***

### Changelog

#### v1.3.0 (August 2026)

- **"Newest first" now actually sorts by newest.** Both sort modes previously returned the same rows in the same order: `most_impressions` asked Meta for its impressions order, and `newest` asked for nothing at all - and Meta's default order *is* impressions-descending. The two modes were verified byte-identical across three queries. Meta's own "Newest" control turned out to use a differently named sort key than the one this actor was sending, so the option is fixed rather than removed.
- **Change tracking is now safe to run in parallel.** Runs share one change-tracking record; each run used to save the copy it had loaded at startup, so simultaneous runs overwrote each other and ads seen by all but the last one were dropped from the baseline (measured: 4 parallel runs delivering 21 ads moved the baseline by 3). Each run now merges only its own ads into the record, re-reading immediately before writing and verifying afterwards. Existing baselines are unaffected - no re-baseline, and no run where everything is reported as new.

#### v1.2.0 (July 2026)

- **Honest delivery accounting**: the run summary now counts ads that actually landed in the dataset. Previously a run that hit its cost limit could log "Total ads: 20" while writing 1 row.
- **Cost-limit handling**: when the run's cost limit is reached the crawl stops immediately, names how many ads were delivered vs requested, and lists the queries it skipped - instead of scraping on and discarding the results.
- **Per-query outcome report**: every run writes an `OUTPUT` key-value record and logs one line per query, distinguishing "Meta has no ads for this term" from "we were blocked".
- **Country is now a dropdown** of all 249 ISO 3166-1 codes, so a country name can no longer fail a started run.
- **Rate limits are no longer reported as empty results**: a throttled response from Meta now fails loudly instead of returning zero ads.
- **Browser fallback memory guard**: refuses to launch below 1 GB instead of being OOM-killed mid-run.
- **No fabricated values**: an unknown ad start date is `null` (previously today's date), unknown page likes are `null` (previously `0`), and Meta's `-1` "not disclosed" impressions sentinel is `null`.

#### v1.1.0

- **Multi-query support**: `searchQueries` array — scrape multiple keywords in one run
- `maxAds` now applies per query (total = maxAds × number of queries)
- Backward compatible: legacy `searchQuery` string still works

#### v1.0.0

- Initial release
- GraphQL interception for reliable data extraction
- Sentiment analysis (AFINN-165)
- Change tracking across runs
- Carousel and video ad support
- Residential proxy support

***

### Keywords

Meta Ad Library Scraper, Facebook Ad Library API, Instagram Ads Scraper, Facebook Ads Data Extraction, Meta Advertising API, Competitor Ad Analysis, Facebook Ad Spy Tool, Social Media Ad Scraper, Ad Creative Research, Facebook Marketing Data, Meta Business Suite Scraper, Facebook Ad Transparency, Political Ads Scraper, Housing Ads Data, Ad Library Export CSV, Facebook Ad Monitoring, Competitor Intelligence Tool, Meta Ads Database, Social Media Marketing Research, Ad Copy Analysis

***

*Built with Apify SDK and Playwright. Data accuracy depends on Meta Ad Library availability.*

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords or brand names to look up in the Meta Ad Library. One entry per search. Tip: search in the advertiser's own language - Meta indexes ad text, so an Arabic brand usually only matches its Arabic spelling.

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

Country whose Ad Library to search. Meta returns only ads shown in this country.

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

How many ads to return per search query. Total ads = this number x number of queries. Each delivered ad is billed, so keep this in line with your run cost limit.

## `activeStatus` (type: `string`):

Which ads to include. Active ads are currently running; 'All ads' also returns ads that already stopped (best when a search returns nothing).

## `adType` (type: `string`):

Filter by ad category

## `mediaType` (type: `string`):

Filter by media type

## `sortMode` (type: `string`):

Which of Meta's two sort orders to request. 'Newest first' returns recently created ads - ideal for finding fresh leads each run. 'Most impressions' returns high-reach ads first - better for competitive research, and is Meta's own default order.

## `analyzeSentiment` (type: `boolean`):

Analyze sentiment of ad copy using AFINN-165 NLP. Adds sentiment\_score and sentiment\_label to output.

## `trackChanges` (type: `boolean`):

Track changes across scheduled runs. Identifies new ads and changes to existing ads.

## `useProxies` (type: `boolean`):

Keep this on. Meta blocks datacenter traffic to the Ad Library; residential proxies are what make the run succeed.

## `proxyGroups` (type: `array`):

Apify proxy groups to route through. RESIDENTIAL is required for Meta in practice.

## Actor input object example

```json
{
  "searchQueries": [
    "running shoes",
    "real estate"
  ],
  "country": "US",
  "maxAds": 20,
  "activeStatus": "active",
  "adType": "all",
  "mediaType": "image",
  "sortMode": "newest",
  "analyzeSentiment": true,
  "trackChanges": true,
  "useProxies": true,
  "proxyGroups": [
    "RESIDENTIAL"
  ]
}
```

# Actor output Schema

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

No description

## `runSummary` (type: `string`):

Per-search outcome. If the run was stopped early, this also lists the searches that never ran (queriesNotRun) and contains a ready-to-paste input for just those (rerunInput), so you never pay twice for ads you already have.

# 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 = {
    "searchQueries": [
        "running shoes",
        "real estate",
        "fitness app"
    ],
    "country": "DE"
};

// Run the Actor and wait for it to finish
const run = await client.actor("webdatalabs/meta-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 = {
    "searchQueries": [
        "running shoes",
        "real estate",
        "fitness app",
    ],
    "country": "DE",
}

# Run the Actor and wait for it to finish
run = client.actor("webdatalabs/meta-ad-library-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "running shoes",
    "real estate",
    "fitness app"
  ],
  "country": "DE"
}' |
apify call webdatalabs/meta-ad-library-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,webdatalabs/meta-ad-library-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/IMMH40vIUcIwnta4A/builds/cqjHucg2F3FMsRGb4/openapi.json
