# Meta Ad Library Scraper — Ad Creatives, Spend & Targeting (`khadinakbar/meta-ad-library-scraper`) Actor

Extract Facebook & Instagram ad creatives, spend ranges, impressions, targeting data, and landing pages from Meta Ad Library $5.00/1K. MCP/API-ready.

- **URL**: https://apify.com/khadinakbar/meta-ad-library-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Marketing, Social media, MCP servers
- **Stats:** 34 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 ad results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are 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 — Ad Creatives, Spend & Targeting

Meta Ad Library Scraper is an Apify Actor for people who need Meta Ad Library records from Facebook, Instagram, and Messenger in a structured dataset. It accepts a keyword, multiple keywords, advertiser Page IDs, Meta Ad Library URLs, or a single ad ID. Each returned record represents one ad and can include creative text, headline, landing page, spend range, impressions, platform placement, languages, region or demographic delivery data, and enrichment fields such as ad summary, detected CTA, ad category, running days, word count, hashtag count, and emoji count. The output is ready for analysis in Apify, downstream automation, or use through Apify MCP.

### Best fit and connected workflows

This Actor fits workflows where the source of truth is Meta Ad Library and the goal is to turn public ad listings into clean records.

It works well when you want to:

- search by topic, brand, or advertiser Page ID
- compare active and inactive ads across countries
- review image and video creatives alongside landing pages
- use spend, impressions, and targeting fields when a Meta access token is provided
- enrich records for AI or MCP pipelines with summary and CTA fields
- run a quick count first with `onlyCount` and then fetch the full dataset

If your workflow starts from a known Facebook Page, `advertiserPageIds` gives you a direct path to all ads from that advertiser. If you already have a Meta Ad Library URL, `startUrls` can capture the filters from the URL and reuse them in the run input.

### Practical scenario

Maya is reviewing a fitness supplement brand that just launched a new campaign. She starts with the brand name in `searchQuery`, limits results to `US`, sets `adStatus` to `ACTIVE`, and keeps `enrichAds` enabled.

The returned record shows:

- `page_name` for the advertiser identity
- `ad_creative_body` and `ad_creative_link_title` for the message
- `landing_page_domain` for the destination site
- `spend_lower` and `spend_upper` for estimated spend
- `impressions_lower` and `impressions_upper` for reach signals
- `ad_summary` and `detected_cta` for quick review

Maya uses the landing page domain and CTA type to decide whether the brand is sending traffic to a product page or a lead capture flow. Her next action is to open the linked creative in `ad_snapshot_url` and compare it with other active ads from the same advertiser.

### Input fields

| Field | Type | Purpose |
|---|---:|---|
| `searchQuery` | string | Search one keyword or phrase in Meta Ad Library. |
| `searchQueries` | array\[string] | Run several keyword searches and merge the results. |
| `metaAccessToken` | string | Meta Graph API access token with `ads_read` permission. |
| `countries` | array\[string] | ISO country codes for ad delivery filtering. Default: `["US"]`. |
| `adStatus` | string | `ALL`, `ACTIVE`, or `INACTIVE`. |
| `adType` | string | Ad category filter such as `ALL` or regulated categories. |
| `mediaType` | string | Creative format filter such as `ALL`, `IMAGE`, or `VIDEO`. |
| `startDate` | string | Include ads running on or after this date. |
| `endDate` | string | Include ads running on or before this date. |
| `maxResults` | integer | Maximum number of ad records to fetch. |
| `sortBy` | string | `impressions_desc` or `most_recent`. |
| `enrichAds` | boolean | Add summary and auto-analysis fields to each record. |
| `providerFallbackEnabled` | boolean | Use configured public-data fallback when the primary path returns no ads. |
| `onlyCount` | boolean | Return only the total number of matching ads. |
| `advertiserPageIds` | array\[string] | Fetch all ads for specific Facebook Page IDs. |
| `startUrls` | array | Paste Meta Ad Library URLs or Facebook Page URLs. |
| `adId` | string | Look up one specific ad by Meta Ad Library ID. |
| `contentLanguages` | array\[string] | Filter creative language by ISO 639-1 code. |
| `publisherPlatforms` | array\[string] | Filter by platform such as Facebook or Instagram. |
| `searchType` | string | `KEYWORD_UNORDERED` or `KEYWORD_EXACT_PHRASE`. |
| `metaAccessTokens` | array | Token pool for high-volume use. |
| `proxyUrls` | array | Custom proxy URLs for web scrape mode. |

#### Focused JSON input example

```json
{
  "searchQuery": "artificial intelligence",
  "countries": ["US", "GB"],
  "adStatus": "ACTIVE",
  "adType": "ALL",
  "mediaType": "ALL",
  "startDate": "a source-provided date",
  "endDate": "a source-provided date",
  "maxResults": 50,
  "sortBy": "impressions_desc",
  "enrichAds": true,
  "providerFallbackEnabled": true,
  "onlyCount": false,
  "publisherPlatforms": ["facebook", "instagram"],
  "searchType": "KEYWORD_UNORDERED"
}
```

### Output fields

Each dataset item represents one ad record. The live dataset contract defines these fields.

| Field | Type | Purpose |
|---|---:|---|
| `ad_id` | string or null | Meta Ad Library ad identifier. |
| `page_id` | string or null | Facebook Page ID for the advertiser. |
| `page_name` | string or null | Advertiser name shown in the library. |
| `ad_creative_body` | string or null | Main ad copy. |
| `ad_creative_bodies` | array or null | Multiple copy variants when present. |
| `ad_creative_link_title` | string or null | Headline or CTA card title. |
| `ad_creative_link_caption` | string or null | Domain shown on the link card. |
| `ad_creative_link_description` | string or null | Link card description text. |
| `ad_snapshot_url` | string or null | Creative preview link in Meta Ad Library. |
| `landing_page_url` | string or null | Advertiser destination URL. |
| `spend_lower` / `spend_upper` | integer or null | Estimated spend range where available. |
| `currency` | string or null | ISO 4217 currency code. |
| `impressions_lower` / `impressions_upper` | integer or null | Estimated impression range where available. |
| `eu_total_reach` | integer or null | EU reach value where available. |
| `delivery_start_date` / `delivery_stop_date` | string or null | Ad run dates. |
| `ad_creation_time` | string or null | Ad creation timestamp. |
| `is_active` | boolean | Whether the ad is currently running. |
| `publisher_platforms` | array or null | Platforms where the ad ran. |
| `languages` | array or null | Creative language codes. |
| `demographic_distribution` | array or null | Age and gender delivery breakdown. |
| `delivery_by_region` | array or null | Regional delivery breakdown. |
| `landing_page_domain` | string or null | Domain extracted from the landing page. |
| `image_urls` | array or null | Direct image URLs when available. |
| `video_urls` | array or null | Direct video URLs when available. |
| `cta_type` | string or null | CTA button type from Meta data. |
| `carousel_cards` | array or null | Carousel card details when present. |
| `search_query` | string or null | Search term used for the record. |
| `ad_summary` | string or null | One-sentence LLM-ready summary. |
| `detected_cta` | string or null | Auto-detected CTA label. |
| `ad_category` | string or null | Auto-classified ad category. |
| `running_days` | integer or null | Number of days the ad has been running. |
| `word_count` | integer | Word count of the ad body. |
| `hashtag_count` | integer | Hashtag count in the ad body. |
| `emoji_count` | integer | Emoji count in the ad body. |
| `country_filter` | string | Country filter applied to the run. |
| `data_mode` | string | Collection mode used for the record. |
| `scraped_at` | string | Extraction timestamp. |

#### Illustrative output record

```json
{
  "ad_id": "23851234567890123",
  "page_id": "123456789",
  "page_name": "Nike",
  "ad_creative_body": "Run faster. Train smarter. Shop now and get free shipping.",
  "ad_creative_link_title": "Shop Nike Air Max 2024",
  "ad_creative_link_caption": "nike.com",
  "ad_snapshot_url": "https://www.facebook.com/ads/archive/render_ad/?id=23851234567890123",
  "landing_page_url": "https://www.nike.com/w/new-shoes",
  "spend_lower": 1000,
  "spend_upper": 5000,
  "currency": "USD",
  "impressions_lower": 100000,
  "impressions_upper": 500000,
  "eu_total_reach": 250000,
  "delivery_start_date": "2024-01-15T00:00:00+0000",
  "delivery_stop_date": "2024-02-28T00:00:00+0000",
  "is_active": true,
  "publisher_platforms": ["facebook", "instagram"],
  "languages": ["en"],
  "landing_page_domain": "nike.com",
  "cta_type": "SHOP_NOW",
  "ad_summary": "Nike ad on facebook/instagram (currently running, links to nike.com): \"Run faster. Train smarter...\"",
  "detected_cta": "shop_now",
  "ad_category": "ecommerce",
  "running_days": 45,
  "word_count": 18,
  "hashtag_count": 3,
  "emoji_count": 2,
  "country_filter": "US",
  "data_mode": "graph_api",
  "scraped_at": "2026-03-28T10:30:00.000Z"
}
```

### How it works

The actor uses Meta Graph API when a valid Meta access token is supplied. In that mode, it can return spend ranges, impressions, demographics, and richer creative data.

When the native Meta Graph API or browser scrape path returns no ads because of a block, timeout, rate limit, or expired token, provider fallback can try configured public Meta Ad Library APIs from ScrapeCreators or SociaVault. The manifest also shows support for public web scraping mode and custom proxy URLs for that path.

`enrichAds` adds derived fields to each record, including `ad_summary`, `detected_cta`, `ad_category`, `running_days`, `word_count`, `hashtag_count`, and `emoji_count`. `onlyCount` returns the match total without downloading ad rows.

### Pricing

This Actor uses pay per event pricing plus Apify platform usage. The primary event is `Ad Result`, charged for each ad scraped. A separate actor start event is also charged by memory allocation.

For example, a run that returns one hundred ads is billed for one hundred `Ad Result` events, plus the actor start event. For the current event definitions and the live Pricing tab, check the Actor page in Apify.

### Use with AI agents (MCP)

This Actor is usable through Apify MCP as an Apify Actor, which lets agents call it as a tool and receive structured ad records back in the dataset.

Actor identity: `khadinakbar/meta-ad-library-scraper`

Tool description: search Meta Ad Library by keyword, advertiser, URL, or ad ID and return one record per ad with creative, spend, impressions, targeting, and landing-page fields.

> Find active Facebook and Instagram ads for the keyword "AI productivity tools" in the US, return up to 50 results, and include enrichment fields for summary and CTA detection.

How to read the output:

- `ad_summary` is the quickest LLM-ready description
- `ad_snapshot_url` points to the creative in Meta Ad Library
- `landing_page_url` and `landing_page_domain` identify the destination
- `spend_lower`/`spend_upper` and `impressions_lower`/`impressions_upper` are ranges when available
- `publisher_platforms`, `languages`, `demographic_distribution`, and `delivery_by_region` support targeting analysis
- `data_mode` shows whether the record came from Graph API, web scrape, or a fallback provider

Scope and provenance:

- Each dataset row represents one ad
- `scraped_at` marks when the record was extracted
- `country_filter` and `search_query` help trace the search context

Pagination and cost guidance:

- Raise `maxResults` for broader coverage
- Use `onlyCount` first when you want a quick estimate
- Use `sortBy: "impressions_desc"` to review higher-reach ads first
- Cost scales with returned ad results under the pay per event model

### Apify API example

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

const client = new ApifyClient({
    token: process.env.APIFY_TOKEN,
});

const run = await client.actor('khadinakbar/meta-ad-library-scraper').call({
    searchQuery: 'AI productivity tools',
    countries: ['US'],
    adStatus: 'ACTIVE',
    maxResults: 25,
    enrichAds: true,
});

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

const datasetItems = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Returned ${datasetItems.items.length} ads`);
```

### Best results and outcome guidance

Use `searchQuery` for topic discovery, `advertiserPageIds` for known brands, and `startUrls` when you already have a filtered Meta Ad Library URL. For focused review, combine `countries`, `adStatus`, `mediaType`, and `publisherPlatforms`. For AI workflows, keep `enrichAds` enabled so the dataset includes summary and classification fields.

### Focused standalone workflow

Meta Ad Library Scraper — Ad Creatives, Spend & Targeting is designed as a focused standalone workflow for the public input and structured output contract described above.

### Design note

I found that the live dataset contract includes `scraped_at` as a required field, while many other fields are optional and may be null depending on the collection path.

### FAQ

**How should I choose between `searchQuery` and `advertiserPageIds`?**\
Use `searchQuery` when you want to discover ads around a theme or brand name. Use `advertiserPageIds` when you already know the Facebook Page IDs and want all ads from those advertisers.

**When should I use `startUrls`?**\
Use `startUrls` when you have a Meta Ad Library URL with filters already set in the browser and want the Actor to reuse those parameters.

**What does `onlyCount` return?**\
It returns the total number of matching ads without downloading full records.

**Which fields are richest with a Meta access token?**\
The input contract says the token unlocks spend ranges, impressions, demographics, image and video URLs, and faster scraping.

**How do I narrow results to a specific market or format?**\
Use `countries`, `adStatus`, `adType`, `mediaType`, `publisherPlatforms`, and `contentLanguages` together.

**What is the output record structure useful for?**\
It is built for ad creative review, targeting analysis, landing-page comparison, and AI or MCP pipelines that need one normalized record per ad.

### Responsible use

Use this Actor in ways that respect Meta Ad Library access, applicable laws, and the terms that apply to your account and environment. Review public ad records carefully, especially when using spend, impression, or targeting fields, since some values are ranges or may be null depending on the data collection path and the ad type.

# Actor input Schema

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

Keyword or phrase to search in Meta Ad Library. Finds all ads mentioning this term across Facebook, Instagram, and Messenger. Example: 'nike running shoes', 'weight loss', 'crypto'. For MCP/API: pass a plain string.

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

Run several keyword searches in one go. Each keyword is scraped separately and results are merged. Example: \["nike", "adidas", "puma"]. Leave empty if using the single keyword above.

## `metaAccessToken` (type: `string`):

Your Meta Graph API access token with ads\_read permission. Unlocks spend ranges, impressions, demographics, image/video URLs, and much faster scraping. Without it the actor uses web scraping mode (slower, fewer fields). Get a free token at: https://developers.facebook.com/tools/explorer/

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

Countries where the ads were shown. Use ISO 3166-1 alpha-2 codes. Examples: US, GB, AU, CA, DE, FR, IN, BR. Default is US. For MCP: pass as array of strings, e.g. \["US", "GB"].

## `adStatus` (type: `string`):

ACTIVE = ads currently running (best for competitor research). INACTIVE = stopped ads. ALL = both active and inactive.

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

Type of ads to include. ALL covers standard commercial ads. Use POLITICAL\_AND\_ISSUE\_ADS for political content, housing/employment/credit for regulated ad categories.

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

Filter by creative format. IMAGE = photo ads only. VIDEO = video ads only. ALL = no filter.

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

Only include ads that were running on or after this date. Format: YYYY-MM-DD. Example: 2024-01-01. Leave empty for no date filter.

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

Only include ads that were running on or before this date. Format: YYYY-MM-DD. Example: 2024-12-31. Leave empty for no date filter.

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

Maximum number of ad records to fetch. 50 = quick sample. 100 = standard run. 500–1000 = deep competitive analysis. Higher = more cost. Default: 100.

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

How to order returned ads. impressions\_desc = highest-reach ads first (best for finding what's working). most\_recent = newest ads first.

## `enrichAds` (type: `boolean`):

Adds extra fields to every ad: ad\_summary (one-line description), detected\_cta (call-to-action type), ad\_category, running\_days, word\_count, hashtag\_count, emoji\_count. Highly recommended for LLM/MCP pipelines. No extra cost.

## `providerFallbackEnabled` (type: `boolean`):

When the native Meta Graph API or browser scrape returns no ads because of a block, timeout, rate limit, or expired token, try the configured ScrapeCreators/SociaVault public Meta Ad Library API fallback. No user cookies required.

## `onlyCount` (type: `boolean`):

Returns only the total number of matching ads without downloading records. Use this to check how many ads exist before running a full scrape. Very fast and cheap.

## `advertiserPageIds` (type: `array`):

Get all ads from specific Facebook Pages by their Page ID. To find a Page ID: go to the page on Facebook → About → Page ID at the bottom. Example: \["123456789", "987654321"]. Use this instead of searchQuery to get all ads from a known brand.

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

Paste URLs directly from facebook.com/ads/library after setting your filters in the browser. The actor extracts all filter parameters automatically. Also accepts Facebook Page URLs to scrape all ads from that page.

## `adId` (type: `string`):

Look up one specific ad by its Meta Ad Library ID (e.g. 23851234567890123). Use this to monitor a single ad or verify it still exists. Requires Meta API token.

## `contentLanguages` (type: `array`):

Only return ads written in these languages. Use ISO 639-1 codes: en (English), es (Spanish), de (German), fr (French), pt (Portuguese). Leave empty for all languages.

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

Filter by which Meta platform the ad ran on. Options: facebook, instagram, messenger, audience\_network, threads. Default includes Facebook and Instagram.

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

KEYWORD\_UNORDERED = all words must appear but in any order (broader). KEYWORD\_EXACT\_PHRASE = words must appear exactly as typed (narrower).

## `metaAccessTokens` (type: `array`):

Add multiple Meta API tokens to distribute rate limits across tokens. The actor picks one randomly per run. Only needed for very high-volume use (1000+ ads per minute). Leave empty if using the single token above.

## `proxyUrls` (type: `array`):

Use your own residential proxies (Webshare, BrightData, Oxylabs, Smartproxy). Format: http://user:pass@host:port. Only applies in web scrape mode (no Meta token). Leave empty to use Apify's built-in proxies.

## Actor input object example

```json
{
  "searchQuery": "artificial intelligence",
  "searchQueries": [],
  "countries": [
    "US"
  ],
  "adStatus": "ALL",
  "adType": "ALL",
  "mediaType": "ALL",
  "maxResults": 100,
  "sortBy": "impressions_desc",
  "enrichAds": true,
  "providerFallbackEnabled": true,
  "onlyCount": false,
  "advertiserPageIds": [],
  "startUrls": [],
  "contentLanguages": [],
  "publisherPlatforms": [
    "facebook",
    "instagram"
  ],
  "searchType": "KEYWORD_UNORDERED",
  "metaAccessTokens": [],
  "proxyUrls": []
}
```

# Actor output Schema

## `OUTPUT` (type: `string`):

URL for the stable terminal outcome record written to the OUTPUT key-value store record.

## `RUN_SUMMARY` (type: `string`):

URL for detailed terminal diagnostics written to the RUN\_SUMMARY key-value store record.

## `datasetUrl` (type: `string`):

URL to access all extracted ad records in JSON format.

# 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": "artificial intelligence",
    "searchQueries": [],
    "countries": [
        "US"
    ],
    "advertiserPageIds": [],
    "startUrls": [],
    "contentLanguages": [],
    "publisherPlatforms": [
        "facebook",
        "instagram"
    ],
    "metaAccessTokens": [],
    "proxyUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/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 = {
    "searchQuery": "artificial intelligence",
    "searchQueries": [],
    "countries": ["US"],
    "advertiserPageIds": [],
    "startUrls": [],
    "contentLanguages": [],
    "publisherPlatforms": [
        "facebook",
        "instagram",
    ],
    "metaAccessTokens": [],
    "proxyUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/meta-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": "artificial intelligence",
  "searchQueries": [],
  "countries": [
    "US"
  ],
  "advertiserPageIds": [],
  "startUrls": [],
  "contentLanguages": [],
  "publisherPlatforms": [
    "facebook",
    "instagram"
  ],
  "metaAccessTokens": [],
  "proxyUrls": []
}' |
apify call khadinakbar/meta-ad-library-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

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