# Meta Ad Library API - Facebook & Instagram Ads Scraper (`thenetaji/meta-ad-library-api-scraper`) Actor

Scrape public Facebook and Instagram ads from Meta Ad Library: search by keyword or Ad Library URL, browse every ad from a known advertiser Page, or find a Page's ID by brand name. Filter by country, status, category, format, platform, and date, and optionally enrich each ad with full details.

- **URL**: https://apify.com/thenetaji/meta-ad-library-api-scraper.md
- **Developed by:** [The Netaji](https://apify.com/thenetaji) (community)
- **Categories:** Social media
- **Stats:** 3 total users, 3 monthly users, 87.5% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.50 / 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 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

## Facebook Ads Library Scraper

The Actor reads public advertising data from the Meta Ad Library and returns it as structured records. It covers three related tasks: searching all advertisers by keyword, collecting every ad belonging to one advertiser Page, and resolving a brand name to the Page ID the other two modes require.

It serves as a Meta Ad Library API for cases the official Ad Library API does not cover. That interface returns ordinary commercial ads only when the audience is in an EU member state or the UK, where the Digital Services Act compels disclosure; a commercial ad targeting the United States alone returns nothing through it, despite being visible on the Ad Library website. It also requires a Meta developer account with identity verification. This Actor reads the same public data the website exposes, across all countries, and requires no Meta credentials.

### Selecting a function

The `scraperType` field determines what a run does. It defaults to `search`.

| Value | Label | Purpose | Required input |
|---|---|---|---|
| `search` | Search Ads | Find ads across all advertisers matching a query | `q`, or a Start URL |
| `page` | Browse page ads | Collect every ad from one advertiser Page | `page_id` |
| `searchPages` | Find advertiser page | Resolve a brand name to its Page ID | `q` |

The three modes form a sequence. A brand name resolved through `searchPages` yields a `pageId`, which becomes the `page_id` for a `page` run.

### Accepted input

| Field | Type | Default | Description |
|---|---|---|---|
| `scraperType` | enum | `search` | Which of the three functions the run performs. |
| `startUrl` | string | — | A Meta Ad Library URL. Its query parameters populate any field left empty. |
| `q` | string | — | Search query in `search` mode; brand or company name in `searchPages` mode. Unused in `page` mode. |
| `page_id` | string | — | Numeric Page ID of the advertiser. Required in `page` mode. |
| `country` | string | `US` | ISO 3166-1 alpha-2 country code. |
| `maxItems` | integer | `50` | Maximum records saved. `0` removes the limit. |
| `enrichAdDetails` | boolean | `false` | Fetches the full detail record for every ad returned. |
| `active_status` | enum | `all` | `all`, `active`, `inactive`. |
| `ad_type` | enum | `ALL` | `ALL`, `POLITICAL_AND_ISSUE_ADS`, `HOUSING_ADS`, `EMPLOYMENT_ADS`, `CREDIT_ADS`. |
| `media_type` | enum | `all` | `all`, `image`, `video`, `meme`. |
| `search_type` | enum | — | `keyword_unordered` or `keyword_exact_phrase`. |
| `publisher_platforms` | array | — | Restricts results to selected Meta platforms. |
| `content_languages` | string | — | Comma-separated ISO 639-1 codes. |
| `date_min` / `date_max` | string | — | Bounds on the ad's active period, `YYYY-MM-DD`. |
| `page_ids` | string | — | Comma-separated Page IDs restricting a search to specific advertisers. |
| `is_targeted_country` | boolean | `false` | Returns only ads specifically targeting `country`. |
| `potential_reach_min` / `_max` | integer | — | Bounds on estimated audience size. |
| `sort_mode` | enum | — | `total_impressions`. Leave empty for default ordering. |
| `sort_direction` | enum | — | `desc`. |

```json
{
  "scraperType": "search",
  "q": "running shoes",
  "country": "US",
  "maxItems": 50,
  "active_status": "active",
  "media_type": "video"
}
```

#### Filters accepted by each mode

Filters are not shared across all three modes. A filter set in a mode that does not accept it is ignored rather than rejected, so a run that appears to disregard a setting is usually a mode mismatch.

| Filter | `search` | `page` | `searchPages` |
|---|---|---|---|
| `country` | yes | yes | yes |
| `active_status`, `media_type`, `publisher_platforms`, `content_languages`, `date_min`, `date_max`, `sort_mode`, `sort_direction` | yes | yes | no |
| `ad_type` | yes | no | yes |
| `search_type`, `page_ids`, `is_targeted_country`, `potential_reach_min`, `potential_reach_max` | yes | no | no |

### Response fields

Ad records, returned by `search` and `page`:

| Field | Contents |
|---|---|
| `ad_archive_id` | Identifier of the ad within the Ad Library |
| `page_id` | Numeric ID of the advertiser's Page |
| `page_name` | Name of the advertiser's Page |
| `is_active` | Whether the ad is currently running |
| `start_date` | Unix timestamp at which the ad began running |
| `end_date` | Unix timestamp at which it stopped; `0` while still active |
| `publisher_platform` | Meta platforms the ad ran on |
| `currency` | Currency of the spend and reach figures |
| `spend` | Estimated spend range, where Meta publishes one |
| `reach_estimate` | Estimated audience reach, where Meta publishes one |
| `categories` | Ad categories reported by Meta |
| `snapshot` | Creative payload: body text, title, call to action, images, videos, link |
| `details` | Full detail record; present only when `enrichAdDetails` is enabled |

Advertiser Page records, returned by `searchPages`:

| Field | Contents |
|---|---|
| `pageId` | Page ID, used as `page_id` in `page` mode |
| `name` | Page name |
| `category` | Facebook category of the Page |
| `likes` | Number of likes on the Page |
| `verification` | Verification status |
| `instagramUsername` | Linked Instagram username, where one exists |

```json
{
  "ad_archive_id": "1234567890123456",
  "page_id": "20531316728",
  "page_name": "Example Brand",
  "is_active": true,
  "start_date": 1751328000,
  "end_date": 0,
  "publisher_platform": ["FACEBOOK", "INSTAGRAM"],
  "currency": "USD"
}
```

### Behaviour of the Start URL

A Meta Ad Library URL supplied as `startUrl` is parsed into input fields, and its values fill only those fields left empty. A field set explicitly always takes precedence over the same parameter in the URL. The URL itself is not forwarded upstream.

Two normalisations are applied because the Ad Library interface exposes options the upstream endpoint does not. Sort metrics other than `total_impressions` are dropped, and ascending sort is converted to descending. The URL therefore continues to drive the run rather than failing validation.

A URL of the "browse this Page's ads" form — one carrying `view_all_page_id`, or `search_type=page` — contains no keyword. Such a URL reroutes the run to `page` mode automatically and supplies `page_id` from the URL, irrespective of the selected `scraperType`.

### Behaviour on partial results

Ads are retrieved through a cursor in pages of 20. Collection ends when the upstream returns no cursor, reports no further pages, or returns an empty page.

A request that fails mid-run does not abort the run or discard what preceded it. The failure is logged, records already collected are retained, and the run finishes normally. A dataset smaller than `maxItems` therefore indicates either that the result set was exhausted or that a page failed, and the run log distinguishes the two.

Enrichment is applied per ad and requires both `ad_archive_id` and `page_id` to be present on the record. An enrichment request that fails leaves that record without a `details` field, does not interrupt the run, and is not charged. Each successful enrichment issues one additional request and one additional billed event, so a 500-ad run with enrichment enabled performs 500 extra requests.

### Frequently asked questions

**Is the Meta Ad Library API free?**
Meta's official Ad Library API costs nothing, but access requires a Meta account, government-ID identity verification, and an approved developer app, and its coverage is narrower than the Ad Library website. Ads about social issues, elections, and politics are fully covered. Ordinary commercial ads are returned only where the audience is in the EU or UK, carry a single `eu_total_reach` figure with no spend or impression data, and are absent entirely for audiences outside Europe. This Actor is paid, needs no Meta account or access token, and is not subject to those restrictions.

**What is the Meta Ad Library?**
A public archive Meta maintains of advertising running across Facebook, Instagram, and its other platforms. Ads about social issues, elections, and politics are retained for seven years and carry spend and reach disclosure. Ordinary commercial ads are visible while running and for roughly a year after delivery ends, after which the record is gone — so historical commercial analysis depends on capturing snapshots as ads run rather than querying the archive later.

**Where is the Meta Ad Library found?**
At `facebook.com/ads/library`. A search performed there produces a URL that can be pasted into `startUrl`, which reproduces the same filters without setting them by hand.

**Why does a filter appear to have no effect?**
Most commonly because the selected mode does not accept it; see the filter table above. `ad_type`, for instance, applies in `search` and `searchPages` but not in `page`. Unaccepted filters are ignored silently rather than raising an error.

**Why are `spend` and `reach_estimate` empty on most records?**
Meta publishes those figures only for ads in regulated categories. For ordinary commercial ads they are absent upstream and are returned empty rather than estimated.

**What causes a run to return fewer records than `maxItems`?**
Either the result set was exhausted, or a page request failed and the run ended early while retaining what it had collected. The run log records which occurred. Narrow filters — a short date range combined with `is_targeted_country`, for example — commonly exhaust a result set well below the limit.

**How is a Page ID obtained?**
Through `searchPages`, which takes a brand name in `q` and returns matching advertiser Pages with their `pageId`. That value is then supplied as `page_id` to a `page` run. A Meta Ad Library URL already containing `view_all_page_id` supplies it automatically.

# Actor input Schema

## `scraperType` (type: `string`):

Choose the workflow for this run.

## `startUrl` (type: `string`):

Paste a Facebook Meta Ad Library search or page URL. Its supported filters are resolved automatically, and anything you set below overrides the URL.

## `q` (type: `string`):

For "Search ads": keyword or phrase to search for. For "Find advertiser page": the brand or company name to look up (e.g. Nike). Not used for "Browse page ads".

## `page_id` (type: `string`):

Numeric ID of the advertiser's Facebook Page whose ads you want. Don't know it? Use the "Find advertiser page" mode to look it up by brand name.

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

ISO 3166-1 alpha-2 country code to target, e.g. US, IN, GB. Leave blank to use US.

## `maxItems` (type: `integer`):

Maximum number of results to return. Set 0 for no limit.

## `enrichAdDetails` (type: `boolean`):

Fetch full details with one extra request for every returned ad. Each successful detail fetch is billed as an enrichment, so this increases both requests and run cost.

## `active_status` (type: `string`):

Return all ads, or only currently active or inactive ones. Leave blank to return all ads.

## `ad_type` (type: `string`):

Limit results to a specific ad category, such as political and issue ads. Leave blank to include all categories.

## `media_type` (type: `string`):

Limit results to a creative format: images, videos, or memes. Leave blank to include all formats.

## `search_type` (type: `string`):

How to match your search query: keywords in any order, or the exact phrase.

## `publisher_platforms` (type: `array`):

Only include ads shown on the selected Meta platforms.

## `content_languages` (type: `string`):

Comma-separated ISO 639-1 language codes to include, e.g. en,hi,es.

## `date_min` (type: `string`):

Only include ads active on or after this date (YYYY-MM-DD).

## `date_max` (type: `string`):

Only include ads active on or before this date (YYYY-MM-DD).

## `page_ids` (type: `string`):

Comma-separated Facebook Page IDs to restrict results to specific advertisers.

## `is_targeted_country` (type: `boolean`):

Only show ads that specifically target the selected country. Leave blank or off to include all ads.

## `potential_reach_min` (type: `integer`):

Only include ads with at least this estimated audience size.

## `potential_reach_max` (type: `integer`):

Only include ads with at most this estimated audience size.

## `sort_mode` (type: `string`):

Order results by a metric. Leave empty for the default order.

## Actor input object example

```json
{
  "scraperType": "search",
  "startUrl": "https://www.facebook.com/ads/library/?q=running%20shoes&country=US",
  "q": "Nike",
  "page_id": "15087023444",
  "country": "US",
  "maxItems": 10,
  "enrichAdDetails": false,
  "content_languages": "en,hi",
  "date_min": "2024-01-01",
  "date_max": "2024-12-31",
  "page_ids": "123456789,987654321"
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing all scraped data

# 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 = {
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("thenetaji/meta-ad-library-api-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 = { "maxItems": 10 }

# Run the Actor and wait for it to finish
run = client.actor("thenetaji/meta-ad-library-api-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 '{
  "maxItems": 10
}' |
apify call thenetaji/meta-ad-library-api-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/gofJQMz7Qd67G6z1T/builds/9LXD21L0aU5uqRw0B/openapi.json
