# Facebook Ad Library Scraper & API - All 6 Meta Platforms (`thodor/meta-ad-library`) Actor

Scrape the Meta Ad Library for competitor research. Paste a Facebook Ad Library URL or pick a keyword + country. Get every matching ad as a spreadsheet or via API: ad copy, images, videos, CTA, page, run dates, spend & reach. Covers FB, Instagram, Messenger, WhatsApp, Threads, Audience Network.

- **URL**: https://apify.com/thodor/meta-ad-library.md
- **Developed by:** [Thodor](https://apify.com/thodor) (community)
- **Categories:** Social media, SEO tools, Lead generation
- **Stats:** 3 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 results

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

## Facebook Ad Library Scraper & API for All 6 Meta Platforms

**Scrape the Meta Ad Library for competitor research, creative intelligence, and ad-transparency monitoring.** Paste a Facebook Ad Library URL or pick a keyword + country, and get every matching ad as a **spreadsheet (CSV / Excel / Google Sheets), as JSON, or via API**. Covers every ad running on **Facebook, Instagram, Messenger, WhatsApp, Audience Network, and Threads**.

Each ad comes back as one row with the fields you actually need: page name & profile, ad copy, images, videos, call-to-action, link destination, run dates, publisher platforms, plus **spend, reach, and targeting** for regulated categories (political/issue/housing/credit/employment ads).

Use it to **scrape Facebook ads**, **extract Instagram ads**, track WhatsApp / Messenger / Threads / Audience Network placements, **spy on competitor creatives**, and feed BI tools, lead-enrichment pipelines, or LLM agents with structured Meta ad data.

Built on the Apify platform: residential proxy rotation, scheduling, integrations, full REST API, and dataset export to spreadsheet (CSV, Excel), JSON, HTML, or RSS out of the box.

### Why use this Meta Ad Library Scraper?

- 🕵️ **Competitor intelligence.** See exactly what ads competitors are running, in which countries, and how long they've been running.
- 🎨 **Creative research.** Discover top-performing ad copy, formats, and call-to-actions in your industry.
- 📈 **Trend analysis.** Sort by total impressions or most recent to spot what's gaining traction.
- ⚖️ **Compliance & transparency.** Track active political, housing, employment, or credit ads in any jurisdiction (with currency, spend, and reach estimates).
- 🌍 **Multi-country coverage.** Issue separate searches per ISO country code in a single run.
- 🔗 **Influence mapping.** Link ads back to the Facebook pages running them, including page-like counts and categories.
- 🧪 **Live-tested filters.** Every input is verified against Meta's GraphQL endpoint. Most scrapers expose UI options that silently don't work for anonymous browsing; this one doesn't.

### How to scrape Facebook Ad Library data

#### Option A (recommended): Paste a search URL from your browser

This is the simplest workflow and works for 95% of cases. The form prefills with a working example URL, so the very first click of **Start** returns results.

1. Go to https://www.facebook.com/ads/library/ in any browser.
2. Set up the filters you want: keyword (`q`), country, ad type (all / political / housing / credit / employment), active status, media type, publisher platform, date range.
3. Copy the full URL from your address bar.
4. In Apify Console, open this actor and paste the URL into the **Ad Library search URLs** input. You can add multiple URLs; the actor scrapes them all in sequence and writes a flat `search_url` field to each row so you can trace results back to their source query.
5. (Optional) Adjust **Max ads per search** (default: 100, max: 1,000,000).
6. Click **Start.** Results stream into the dataset as ads are found, so you can begin downloading partial results immediately.

#### Option B: Use structured filters (no browser needed)

If you'd rather not paste URLs (e.g. you're templating runs across many keyword × country combinations from a spreadsheet, or wiring this into an automation), open the **Structured filters** section in the actor input and fill them directly:

- **Search terms** + **Countries**: cross-product becomes one search per combination (3 terms × 5 countries = 15 searches in one run).
- **Ad category / Active status / Media type / Search type / Sort by / Publisher platforms / Start date from-to**: every filter from Facebook's own Ad Library UI is exposed and labelled in plain English.

Click **Start** — same as Option A.

#### Option C: Call it as an API

The actor is callable via the Apify REST API and webhooks with the same input schema as the UI. Useful for scheduled scrapes, lead-enrichment pipelines, n8n / Make / Zapier workflows, and any LLM agent stack. See the actor's **API** tab in Apify Console for the exact endpoint and example `curl` calls.

### Use case recipes

Pick the recipe that matches your goal and follow the click-by-click steps. Recipes using **Search terms + Countries** require opening the **Structured filters** section in the actor input (or you can paste a URL with those filters baked in).

#### 🎨 Find the highest-performing creatives in your industry

**Goal:** pull the top-spending ads for a category across several countries.

**What to fill in (in Structured filters):**
- **Search terms:** type your category keywords, one per line (e.g. `weight loss`, `fitness app`)
- **Countries:** type the country codes you care about, one per line (e.g. `US`, `GB`, `CA`)
- Leave everything else at default.

The actor will run one search per keyword × country combination (so 2 keywords × 3 countries = 6 separate sorted lists, biggest spenders per query first).

#### 📅 Monitor newly-launched ads in your niche (weekly schedule)

**Goal:** catch new creative launches in your industry, e.g. the last 7 days. Pair with Apify's built-in Schedules to run it every Monday.

**What to fill in (in Structured filters):**
- **Search terms:** your niche keywords (e.g. `crypto`, `trading bot`)
- **Countries:** the countries you care about (e.g. `US`)
- **Sort by:** change from the default to **"Most recent (grouped by month)"**. This is important — the default "Total impressions" sort silently ignores the lower date bound.
- **Start date from:** pick the date one week ago in the date picker.
- **Active status:** leave at `active`.

When the run finishes, schedule it weekly via the **Schedules** tab in Apify Console.

#### ⚖️ Political, housing, employment, or credit ad transparency

**Goal:** get the regulated-category-only fields — `currency`, `spend` (range like `"$600K - $700K"`), `reach_estimate`, `impressions_text` / `impressions_index`, and `targeted_or_reached_countries`. **These columns are empty for normal commercial ads — you must set `adType` to a regulated category to get them.**

**What to fill in (in Structured filters):**
- **Search terms:** your topic (e.g. `election`, `vote`, `mortgage`)
- **Countries:** the jurisdiction (e.g. `US`)
- **Ad category:** change from "All ads" to **"Issues, elections or politics"** (or Housing / Employment / Financial products and services, depending on what you're tracking).
- **Active status:** set to **"Active + inactive"** to also get historical ads (politics ads are kept for 7 years).

#### 📱 Threads / WhatsApp / Audience Network analysis

**Goal:** see which brands are running ads on Meta's lesser-known surfaces (most competitor scrapers only return Facebook + Instagram).

**What to fill in (in Structured filters):**
- **Search terms:** your niche (e.g. `fintech`)
- **Countries:** your market (e.g. `US`)
- **Publisher platforms:** tick **only** the surfaces you want — `Threads`, or `WhatsApp`, or `Audience Network`, or any combination. Leaving this empty returns ads from all surfaces.

#### 🌍 Multi-country B2B lead research

**Goal:** find every active ad targeting a specific non-US country for a niche, then enrich the landing pages into a contact list.

**What to fill in (in Structured filters):**
- **Search terms:** your niche, in the local language too if relevant (e.g. `accounting software`, `boekhouder`)
- **Countries:** the target market (e.g. `BE` for Belgium)
- **Publisher platforms:** tick `Facebook` and `Instagram` (skip Threads/WhatsApp for B2B).
- **Active status:** leave at `active`.

When the run finishes, take the `link_url` column from the output spreadsheet and feed it into the [Email Extractor & Lookup API](https://apify.com/thodor/apify-email-scraper-tool) to auto-find contact emails on each landing page.

#### 🕵️ Spy on a single competitor's ads

**Goal:** see every ad one specific brand is currently running, biggest spenders first. No Structured filters needed.

**Steps:**
1. Open the brand's Facebook page in your browser.
2. Click the **"Page transparency"** section, then click **"See all"** under "Ads From This Page". This opens the Ad Library showing only that brand's ads.
3. Copy the URL from your address bar.
4. In the actor's input, paste it into **Ad Library search URLs** (replacing the prefilled crypto example).
5. Click **Start.** That's it — defaults take care of the rest (active ads only, sorted by biggest spenders).

### Input

Every input is optional, except that you must provide either `startUrls` or `searchTerms` (or both; they're additive). Fields marked **Structured** are under the collapsible **Structured filters** section in the form.

| Field | Section | Description |
|---|---|---|
| `startUrls` | Top level | One or more `facebook.com/ads/library` URLs copied from your browser. Prefilled with a working crypto/US example. |
| `maxAdsPerSearch` | Top level | Max unique ads to collect per search. Default: `100`. Max: `1,000,000`. Set to `0` for unlimited. |
| `searchTerms` | Structured | Keywords to search for (each term × country combination becomes one search). |
| `countries` | Structured | ISO country codes; defaults to `["US"]`. Use `["ALL"]` for global. |
| `adType` | Structured | `all` (default), `political_and_issue_ads`, `housing_ads`, `employment_ads`, `credit_ads`. |
| `activeStatus` | Structured | `active` (default), `inactive`, `all`. |
| `mediaType` | Structured | `all` (default), `image`, `video`, `meme`, `image_and_meme`, `none`. |
| `searchType` | Structured | `keyword_unordered` (default), `keyword_exact_phrase`. |
| `sortBy` | Structured | `total_impressions` (default, high to low — best for competitor analysis) or `relevancy_monthly_grouped` (most recent, grouped by month — best with a date filter). |
| `publisherPlatforms` | Structured | Any of `facebook`, `instagram`, `messenger`, `whatsapp`, `audience_network`, `threads`. Empty = all. |
| `startDateFrom` / `startDateTo` | Structured | `YYYY-MM-DD` bounds on ad start date. |

Example input (API / programmatic — section grouping doesn't apply here, just key names):

```json
{
  "startUrls": [
    {"url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&q=crypto&search_type=keyword_unordered"}
  ],
  "searchTerms": ["nike", "adidas"],
  "countries": ["US", "GB"],
  "publisherPlatforms": ["facebook", "instagram", "threads"],
  "startDateFrom": "2025-01-01",
  "maxAdsPerSearch": 100
}
````

### Output

Each ad is written to the dataset as a flat row. **Download as a spreadsheet (CSV or Excel)** for direct use in Google Sheets, Airtable, or Looker, or grab JSON / HTML / RSS / API for piping into BI tools, LLM agents, and automation platforms.

> ⚠️ **Spend, reach, and impressions data is ONLY available for regulated ad categories** — political/issue, housing, employment, and credit ads. **For normal commercial ads these columns will always be empty.** This is a Meta policy (they only legally have to disclose ad finances for regulated categories), not a scraper limitation. To get spend/reach data, set **Ad category** to one of the regulated options when running the actor.

Some ads return placeholder text like `{{product.name}}` or `{{product.brand}}` in the title and body. Those are **DCO (Dynamic Creative Optimization)** ads where Meta serves a different product per viewer from the same template — see the [DCO FAQ](#faq-disclaimers-and-support) for how to filter them out using the `is_dynamic_creative` column.

### Data fields

| | Field | Description |
|---|---|---|
| 🆔 | `ad_archive_id` | Facebook's stable ID for this ad |
| 🟢 | `is_active` | Whether the ad is currently running |
| 📄 | `page_id`, `page_name`, `page_profile_uri` | The Facebook page running the ad |
| 📊 | `page_categories`, `page_like_count` | Page metadata |
| 🎨 | `display_format` | `IMAGE`, `VIDEO`, `DCO` (dynamic creative), `DPA` (dynamic product), `CAROUSEL`, etc. |
| 🧬 | `is_dynamic_creative` | `true` when the ad copy contains template placeholders like `{{product.name}}` (see FAQ below). Use this to filter DCO/DPA template ads out of a spreadsheet in one click. |
| 📝 | `title`, `body_text`, `caption` | Ad copy. For DCO/DPA ads these may contain `{{product.name}}`, `{{product.brand}}`, `{{product.description}}` etc. placeholders rather than literal text |
| 🔘 | `cta_text`, `cta_type` | Call-to-action button label and type |
| 🔗 | `link_url`, `link_description` | Where the ad sends the user |
| 🖼️ | `image_urls` | Direct CDN URLs for image creatives |
| 🎬 | `video_urls` | Direct CDN URLs for video creatives |
| 🃏 | `cards` | For carousel/DCO ads: array of per-card creative (title, body, link, image) |
| 📱 | `publisher_platform` | Which Meta surfaces ran the ad: `FACEBOOK`, `INSTAGRAM`, `MESSENGER`, `THREADS`, `WHATSAPP`, `AUDIENCE_NETWORK` |
| 📅 | `start_date`, `end_date` | ISO 8601 UTC strings (e.g. `"2026-05-23T05:36:37Z"`). For active ads, `end_date` is `null` and `start_date` is derived from the actual `total_active_time` (Meta's anonymous endpoint doesn't expose real delivery windows for non-political ads). |
| 🏷️ | `categories` | Ad's policy categories, e.g. political, housing, credit, employment |
| 🚩 | `contains_sensitive_content`, `contains_digital_created_media` | Policy flags |
| 💰 | `currency`, `spend`, `reach_estimate`, `impressions_text`, `impressions_index` | **⚠️ POLITICAL ADS ONLY.** Null for all normal commercial ads. `spend` is a string range like `"$600K - $700K"` or `">$1M"`. `reach_estimate` and `impressions_text` are string ranges. **`impressions_index` is the only numeric version** — use it to sort competitors by impressions in a spreadsheet. |
| 🌍 | `targeted_or_reached_countries` | **⚠️ POLITICAL ADS ONLY.** Populated for cross-border political campaigns; empty for single-country regulated ads. |
| 🔍 | `search_url` | Which input URL this ad came from (useful when scraping multiple searches) |

#### Raw JSON examples (for developers)

The data fields table above is the canonical reference. The blocks below show the raw row shape you'll get from the API / JSON export, in case you're piping the output into a script.

**Normal commercial ad** — political/transparency fields are present but empty (Meta only publishes those for regulated ads).

```json
{
  "ad_archive_id": "1361967839295138",
  "is_active": true,
  "page_id": "170402436152087",
  "page_name": "Crypto Fund Trader",
  "page_profile_uri": "https://www.facebook.com/cryptofundtrader/",
  "page_categories": ["Internet company", "Education"],
  "page_like_count": 2342,
  "display_format": "DCO",
  "is_dynamic_creative": true,
  "title": "{{product.name}}",
  "body_text": "$19M+ in performance rewards processed. 50,000 traders completed virtual evaluations.",
  "caption": "cryptofundtrader.com",
  "cta_text": "Learn more",
  "cta_type": "LEARN_MORE",
  "link_url": "https://cryptofundtrader.com/?utm_source=meta&...",
  "image_urls": [],
  "video_urls": ["https://video.xx.fbcdn.net/..."],
  "cards": [{"title": "...", "body": "...", "link_url": "...", "cta_text": "..."}],
  "publisher_platform": ["FACEBOOK", "INSTAGRAM", "MESSENGER"],
  "start_date": "2025-11-07T20:00:00Z",
  "end_date": null,
  "categories": ["UNKNOWN"],
  "contains_sensitive_content": false,
  "contains_digital_created_media": false,
  "currency": null,
  "spend": null,
  "reach_estimate": null,
  "impressions_text": null,
  "impressions_index": null,
  "targeted_or_reached_countries": [],
  "search_url": "https://www.facebook.com/ads/library/?..."
}
```

**Political / regulated ad** — same schema, but the bottom block is populated because **Ad category** was set to `political_and_issue_ads` (or `housing_ads` / `employment_ads` / `credit_ads`). `spend`, `reach_estimate`, and `impressions_text` are **string ranges**; `impressions_index` is the only numeric column.

```json
{
  "ad_archive_id": "352695862528588",
  "is_active": true,
  "page_id": "20531316728",
  "page_name": "Facebook App",
  "categories": ["POLITICAL"],
  "currency": "USD",
  "spend": "$600K - $700K",
  "reach_estimate": ">1M",
  "impressions_text": ">1M",
  "impressions_index": 39,
  "targeted_or_reached_countries": ["US", "CA"],
  "search_url": "https://www.facebook.com/ads/library/?ad_type=political_and_issue_ads&..."
}
```

### Tips

- **Parallelism.** To go faster, **add more search URLs** (or more `searchTerms` × `countries` combinations) rather than trying to scale a single search. Workers within one search paginate the same sorted list and waste requests on duplicates beyond ~5 parallel workers.
- **Country filter matters.** `country=ALL` returns Facebook's globally-sorted top ads (heavily US-dominated). Use specific country codes (e.g. `country=BE` for Belgium-targeted ads) for non-US scrapes.
- **Sort order.** Two modes are honored server-side for anonymous browsing: **Most recent (monthly grouped)** (default; surfaces newly-launched ads, respects both ends of the date filter) and **Total impressions** (biggest spenders first; often returns older very-high-spend creatives, and only respects the upper end of the date filter). FB's UI exposes "Creation time / Start date / End date" but those sort modes are not actually honored for anonymous requests; the actor maps them to "Most recent" so pasted URLs still work.
- **Date range filter.** Use `start_date[min]` and `start_date[max]` in pasted URLs (FB UI's "Start date" picker), or the `Start date from` / `Start date to` inputs. Works most reliably with the "Most recent" sort.
- **Ad type filter.** Change `ad_type` from `all` to `political_and_issue_ads` (or housing, credit, employment) to scope to regulated ad categories, which return additional fields like spend, reach, and targeting.
- **Anti-bot engineering.** The actor uses residential sticky-session proxies, Chrome TLS impersonation (Meta blocks plain-Python TLS fingerprints), and an auto-solver for Facebook's `rd_challenge` HTTP-403 gate. You don't need to configure any of this; it's hardcoded as the default because anything else gets rate-limited within seconds.

### Other Apify Actors you might like

If you're using this for competitive intelligence or lead enrichment, these pair well:

- [**TikTok Comment Scraper**](https://apify.com/thodor/tiktok-comments-scraper): extract comments, usernames, timestamps, likes & reply counts from any TikTok username or video URL. Useful for social listening alongside Meta ad data.
- [**Email Extractor & Lookup API**](https://apify.com/thodor/apify-email-scraper-tool): bulk-extract emails from any list of domains (e.g. the `link_url` pages this actor finds). Auto-discovers contact pages and verifies domains.
- [**CMS & Tech Stack Detector**](https://apify.com/thodor/apify-cms-detector): identify the CMS, frameworks, analytics, payment processors, and ecommerce add-ons on competitor sites you discover through their ads.
- [**Reverse Image Search API**](https://apify.com/thodor/google-lens-exact-matches): find where an ad creative appears elsewhere on the web (Instagram, TikTok, eBay, Amazon, etc.) using Google Lens exact-match search.
- [**Google Maps Places API**](https://apify.com/thodor/google-maps-scraper-with-reviews): 60+ business attributes per place (names, phones, websites, hours, reviews, coordinates). Good for B2B lead lists.

### FAQ, disclaimers, and support

**Is it legal to scrape the Facebook Ad Library?** The Facebook Ad Library is a public transparency tool that Meta provides intentionally to let anyone see active ads. This actor only retrieves data that is visible to any logged-out browser visiting the same URLs. Always respect Meta's Terms of Service and your local laws when using scraped data.

**Why does some ad copy look like `{{product.name}}` instead of real text?** Those ads are **DCO (Dynamic Creative Optimization)** or **DPA (Dynamic Product Ads)**. The advertiser uploads a template like `"Shop {{product.name}} from {{product.brand}} today"` and links it to a Facebook Commerce Manager product catalog. At render time, Meta picks the right product per viewer and substitutes the placeholder, so each user sees a different rendered ad from the same template. Because there's no single "rendered" ad, the Ad Library (and therefore every scraper, including this one) returns the raw template with placeholders intact. Use the **`is_dynamic_creative`** column to filter these out of your spreadsheet in one click if you only want literal ad copy.

**Feedback:** open an issue on the actor's Issues tab if anything is broken or missing a field you need.

# Actor input Schema

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

One or more Facebook Ad Library URLs copied from your browser. Configure a search at https://www.facebook.com/ads/library/, then paste the URL here. You can add multiple URLs; each one becomes a separate search.

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

Hard cap on unique ads to collect per search (each URL or each search-term × country combination is one search). Set to 0 for no limit.

## `searchTerms` (type: `array`):

(Optional) Keywords to search for instead of (or in addition to) pasting URLs. Each term × country combination produces one search.

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

ISO country codes (e.g. US, BE, DE, GB) that target ads aim at. Use 'ALL' for global. Each country produces a separate search.

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

Regulated ad categories return additional fields like spend, reach, and targeting (Meta only publishes those for political/housing/employment/credit ads).

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

Currently running ads, or include inactive (ended) ads as well.

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

Filter by ad creative type.

## `searchType` (type: `string`):

How the keyword is matched.

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

Sort order for returned ads. 'Total impressions' (default) surfaces the biggest-spending competitor ads first, best for competitive intelligence. 'Most recent' surfaces newly-launched ads and is best when you set a date-range filter (it honors both ends of the range; 'Total impressions' only honors the upper bound).

## `publisherPlatforms` (type: `array`):

Filter to ads that ran on the selected Meta surfaces. Empty = all platforms.

## `startDateFrom` (type: `string`):

(Optional) Only include ads that started on or after this date. Format: YYYY-MM-DD.

## `startDateTo` (type: `string`):

(Optional) Only include ads that started on or before this date. Format: YYYY-MM-DD.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=crypto&search_type=keyword_unordered&sort_data%5Bdirection%5D=desc&sort_data%5Bmode%5D=total_impressions"
    }
  ],
  "maxAdsPerSearch": 100,
  "countries": [
    "US"
  ],
  "adType": "all",
  "activeStatus": "active",
  "mediaType": "all",
  "searchType": "keyword_unordered",
  "sortBy": "total_impressions",
  "publisherPlatforms": []
}
```

# Actor output Schema

## `results` (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 = {
    "startUrls": [
        {
            "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=crypto&search_type=keyword_unordered&sort_data%5Bdirection%5D=desc&sort_data%5Bmode%5D=total_impressions"
        }
    ],
    "maxAdsPerSearch": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("thodor/meta-ad-library").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 = {
    "startUrls": [{ "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=crypto&search_type=keyword_unordered&sort_data%5Bdirection%5D=desc&sort_data%5Bmode%5D=total_impressions" }],
    "maxAdsPerSearch": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("thodor/meta-ad-library").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 '{
  "startUrls": [
    {
      "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=crypto&search_type=keyword_unordered&sort_data%5Bdirection%5D=desc&sort_data%5Bmode%5D=total_impressions"
    }
  ],
  "maxAdsPerSearch": 100
}' |
apify call thodor/meta-ad-library --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Facebook Ad Library Scraper & API - All 6 Meta Platforms",
        "description": "Scrape the Meta Ad Library for competitor research. Paste a Facebook Ad Library URL or pick a keyword + country. Get every matching ad as a spreadsheet or via API: ad copy, images, videos, CTA, page, run dates, spend & reach. Covers FB, Instagram, Messenger, WhatsApp, Threads, Audience Network.",
        "version": "0.3",
        "x-build-id": "Vd3UQnlu48t1To22Z"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/thodor~meta-ad-library/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-thodor-meta-ad-library",
                "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/thodor~meta-ad-library/runs": {
            "post": {
                "operationId": "runs-sync-thodor-meta-ad-library",
                "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/thodor~meta-ad-library/run-sync": {
            "post": {
                "operationId": "run-sync-thodor-meta-ad-library",
                "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": {
                    "startUrls": {
                        "title": "Ad Library search URLs",
                        "type": "array",
                        "description": "One or more Facebook Ad Library URLs copied from your browser. Configure a search at https://www.facebook.com/ads/library/, then paste the URL here. You can add multiple URLs; each one becomes a separate search.",
                        "default": [
                            {
                                "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=crypto&search_type=keyword_unordered&sort_data%5Bdirection%5D=desc&sort_data%5Bmode%5D=total_impressions"
                            }
                        ],
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "maxAdsPerSearch": {
                        "title": "Max ads per search",
                        "minimum": 0,
                        "maximum": 1000000,
                        "type": "integer",
                        "description": "Hard cap on unique ads to collect per search (each URL or each search-term × country combination is one search). Set to 0 for no limit.",
                        "default": 100
                    },
                    "searchTerms": {
                        "title": "Search terms",
                        "type": "array",
                        "description": "(Optional) Keywords to search for instead of (or in addition to) pasting URLs. Each term × country combination produces one search.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "countries": {
                        "title": "Countries",
                        "type": "array",
                        "description": "ISO country codes (e.g. US, BE, DE, GB) that target ads aim at. Use 'ALL' for global. Each country produces a separate search.",
                        "default": [
                            "US"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "adType": {
                        "title": "Ad category",
                        "enum": [
                            "all",
                            "political_and_issue_ads",
                            "housing_ads",
                            "employment_ads",
                            "credit_ads"
                        ],
                        "type": "string",
                        "description": "Regulated ad categories return additional fields like spend, reach, and targeting (Meta only publishes those for political/housing/employment/credit ads).",
                        "default": "all"
                    },
                    "activeStatus": {
                        "title": "Active status",
                        "enum": [
                            "active",
                            "inactive",
                            "all"
                        ],
                        "type": "string",
                        "description": "Currently running ads, or include inactive (ended) ads as well.",
                        "default": "active"
                    },
                    "mediaType": {
                        "title": "Media type",
                        "enum": [
                            "all",
                            "image",
                            "video",
                            "meme",
                            "image_and_meme",
                            "none"
                        ],
                        "type": "string",
                        "description": "Filter by ad creative type.",
                        "default": "all"
                    },
                    "searchType": {
                        "title": "Search type",
                        "enum": [
                            "keyword_unordered",
                            "keyword_exact_phrase"
                        ],
                        "type": "string",
                        "description": "How the keyword is matched.",
                        "default": "keyword_unordered"
                    },
                    "sortBy": {
                        "title": "Sort by",
                        "enum": [
                            "total_impressions",
                            "relevancy_monthly_grouped"
                        ],
                        "type": "string",
                        "description": "Sort order for returned ads. 'Total impressions' (default) surfaces the biggest-spending competitor ads first, best for competitive intelligence. 'Most recent' surfaces newly-launched ads and is best when you set a date-range filter (it honors both ends of the range; 'Total impressions' only honors the upper bound).",
                        "default": "total_impressions"
                    },
                    "publisherPlatforms": {
                        "title": "Publisher platforms",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Filter to ads that ran on the selected Meta surfaces. Empty = all platforms.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "facebook",
                                "instagram",
                                "messenger",
                                "whatsapp",
                                "audience_network",
                                "threads"
                            ],
                            "enumTitles": [
                                "Facebook",
                                "Instagram",
                                "Messenger",
                                "WhatsApp",
                                "Audience Network",
                                "Threads"
                            ]
                        },
                        "default": []
                    },
                    "startDateFrom": {
                        "title": "Start date from",
                        "type": "string",
                        "description": "(Optional) Only include ads that started on or after this date. Format: YYYY-MM-DD."
                    },
                    "startDateTo": {
                        "title": "Start date to",
                        "type": "string",
                        "description": "(Optional) Only include ads that started on or before this date. Format: YYYY-MM-DD."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
