# Facebook Ad Library Scraper (`santamaria-automations/facebook-ad-library-scraper`) Actor

Search Meta's public Ad Library without login or API key. Get ad text, creatives, spend range, impressions, platforms and funding entity, by keyword or for a specific Facebook Page. $0.0008 per ad plus $0.005 per run start.

- **URL**: https://apify.com/santamaria-automations/facebook-ad-library-scraper.md
- **Developed by:** [NanoScrape](https://apify.com/santamaria-automations) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 ad scrapeds

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

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Facebook Ad Library Scraper

Scrape any ad from [Meta's public Ad Library](https://www.facebook.com/ads/library/): Facebook, Instagram, WhatsApp, Threads, Messenger, Audience Network. No login, no API key, no access token.

### Why this scraper

- **Paste any Ad Library URL**: the filters in the URL (country, ad type, active status, media type, publisher platforms, content languages, page IDs, date range, sort) are parsed automatically. Apply filters in your browser, copy the URL, paste it here.
- **Full creative data**: ad text, headline, link, call to action, every image, every video (HD, SD, preview), every carousel card with its own link and CTA. Meta's raw creative object is passed through in `snapshot`, so new fields are never lost.
- **Page info**: page name, ID, profile picture, page likes, categories.
- **Political and issue ads**: spend range, reach range and impressions as Meta publishes them.
- **EU ad transparency details (reach, targeting, payer)**: switch on `includeAdDetails` to get total EU reach, reach by country, age and gender, targeting and the declared payer and beneficiary for each ad.
- **Fast and light**: about 1,000 ads in roughly 3 minutes.
- **Pay-per-result**: you pay for the ads you receive.

### Input sources (mix and match)

| Field | Example | Use when |
|---|---|---|
| `searchUrls` | `https://www.facebook.com/ads/library/?active_status=all&country=DE&q=nike&search_type=keyword_exact_phrase&publisher_platforms[0]=instagram&start_date[min]=2025-06-01` | You've already built a filtered view in the browser |
| `searchQueries` | `["Tesla Model 3", "electric vehicles"]` | Quick keyword searches across all of Meta's network |
| `pageIds` | `["15087023444"]` | You know the advertiser's numeric Page ID and want all their ads |
| `advertiserNames` | `["Baulig Consulting"]` | You know the brand name (searched as exact phrase) |

### Filters (apply to keyword / page / advertiser searches)

> **Note**: when you paste a `searchUrl`, filters from that URL take precedence. The fields below apply to `searchQueries`, `pageIds`, and `advertiserNames`.

| Filter | Values | Default |
|---|---|---|
| `country` | ISO code (`US`, `GB`, `DE`, ...) or `ALL` | `ALL` |
| `adType` | `ALL`, `POLITICAL_AND_ISSUE_ADS`, `HOUSING_ADS`, `EMPLOYMENT_ADS`, `CREDIT_ADS` | `ALL` |
| `activeStatus` | `ALL`, `ACTIVE`, `INACTIVE` | `ALL` |
| `mediaType` | `ALL`, `IMAGE`, `VIDEO`, `MEME`, `NONE` | `ALL` |
| `publisherPlatforms` | array of `facebook`, `instagram`, `messenger`, `audience_network`, `whatsapp`, `threads`, `oculus` | all |
| `contentLanguages` | ISO 639-1 codes (`en`, `de`, ...) | all |
| `searchType` | `keyword_unordered` (broad) or `keyword_exact_phrase` (strict) | `keyword_unordered` |
| `maxAdsPerInput` / `maxResults` | ads per source / total ads (0 = no total limit) | 20 / 0 |
| `sortBy` | `total_impressions_DESC`, `total_impressions_ASC`, `time_active_DESC`, `time_active_ASC` (Meta has no newest-first sort) | relevancy |
| `startDateMin` / `startDateMax` | `YYYY-MM-DD` | none |
| `includeAdDetails` | `true` adds EU ad transparency details (reach, targeting, payer) to every ad. Runs take longer because each ad needs one extra lookup | `false` |

### What you get

One row per ad. Spend and reach are published by Meta only for political and issue ads, so they are empty for other ads. Meta may add fields over time; they are passed through in `snapshot`.

| Field | Type | Description |
|---|---|---|
| `ad_archive_id` | string | Unique Ad Library archive ID |
| `ad_id` | string | Internal ad ID (rare) |
| `collation_id` | string | Meta's grouping ID for ad variants (group by it to see distinct creatives) |
| `collation_count` | integer | Number of ad variants in this group |
| `page_id` | string | Facebook Page ID of the advertiser |
| `page_name` | string | Display name of the advertiser's Page |
| `page_is_deleted` | boolean | Whether the advertiser Page has been deleted |
| `page_like_count` | integer | Likes on the advertiser's Page |
| `page_profile_picture_url` | string | Direct URL to the Page's profile picture |
| `page_profile_uri` | string | Public URL of the Page |
| `is_active` | boolean | Whether the ad is currently running |
| `start_date` | integer | Unix timestamp when the ad started running |
| `end_date` | integer | Unix timestamp when the ad stopped running (empty if still active) |
| `start_date_formatted` | string | Start date as YYYY-MM-DD |
| `end_date_formatted` | string | End date as YYYY-MM-DD |
| `total_active_time` | integer | Total seconds the ad has been active |
| `publisher_platform` | array | Platforms where the ad runs (FACEBOOK, INSTAGRAM, MESSENGER, AUDIENCE_NETWORK, WHATSAPP, THREADS) |
| `targeted_or_reached_countries` | array | Countries the ad targets or reaches |
| `categories` | array | Meta's ad categories |
| `display_format` | string | Creative format (IMAGE, VIDEO, CAROUSEL, DCO, ...) |
| `cta_type` | string | Call-to-action button type (LEARN_MORE, SHOP_NOW, ...) |
| `cta_text` | string | Display text of the call-to-action button |
| `link_url` | string | Destination URL the ad links to |
| `link_description` | string | Description text below the link title |
| `title` | string | Ad headline |
| `body_text` | string | Main body text of the ad |
| `ad_caption` | string | Caption on the link card (usually the domain) |
| `snapshot` | object | Meta's full creative object: body, images\[], videos\[], cards\[] for carousels, page categories, byline, disclaimer label and more |
| `currency` | string | Currency code for spend figures |
| `spend` | string | Spend range as text, for example `>$1M` (political and issue ads only) |
| `reach_estimate` | string | Reach range as text, for example `>1M` (political and issue ads only) |
| `impressions_with_index` | object | Impression range with text representation |
| `has_user_reported` | boolean | Whether users have reported the ad |
| `report_count` | integer | Number of user reports |
| `is_aaa_eligible` | boolean | Whether the ad is eligible for ad authorization (political and issue ads) |
| `gated_type` | string | Ad gating status (ELIGIBLE, GATED, ...) |
| `hide_data_status` | string | Whether transparency data is hidden (NONE, HIDDEN, ...) |
| `contains_digital_created_media` | boolean | Whether the ad contains AI-generated or digitally altered media |
| `contains_sensitive_content` | boolean | Whether Meta flagged sensitive content |
| `is_violating_eu_siep` | boolean | Whether the ad violates the EU policy on sensitive issues, elections or politics |
| `violation_types` | array | Policy violations associated with the ad |
| `verified_voice_context` | object | Verified-voice transparency information |
| `state_media_run_label` | object | State-controlled media label |
| `menu_items` | array | Interactive menu items in the ad |
| `fev_info` | object | External review information |
| `regional_regulation_data` | object | Regional regulatory data |
| `aaa_info` | object | Ad authorization data, included when Meta returns it |
| `transparency_by_location` | object | Per-jurisdiction transparency data, included when Meta returns it |
| `advertiser` | object | Advertiser metadata, included when Meta returns it |
| `total_advertiser_spend_lower` | integer | Lifetime Page spend, lower bound (only when Meta returns it) |
| `total_advertiser_spend_upper` | integer | Lifetime Page spend, upper bound (only when Meta returns it) |
| `total_advertiser_spend_currency` | string | Currency of the lifetime Page spend |
| `eu_total_reach` | integer | Total EU reach of the ad (with `includeAdDetails`; empty when the ad was not delivered in the EU) |
| `targets_eu` | boolean | Whether the ad targets the EU (with `includeAdDetails`) |
| `beneficiary` | string | Beneficiary declared by the advertiser (with `includeAdDetails`) |
| `payer` | string | Payer declared by the advertiser (with `includeAdDetails`) |
| `target_ages` | string | Targeted age range, for example `18-65+` (with `includeAdDetails`) |
| `target_gender` | string | Targeted gender, for example `All` (with `includeAdDetails`) |
| `target_locations` | array | Targeted locations, an empty list when unknown (with `includeAdDetails`) |
| `reach_breakdown` | array | EU reach per country and age range: `country`, `age_range`, `male`, `female`, `unknown` (with `includeAdDetails`) |
| `ad_details_status` | string | `ok`, `not_eu` (ad not delivered in the EU) or `failed` (details could not be fetched) (with `includeAdDetails`) |
| `ad_library_url` | string | Direct link to the ad in the Ad Library |
| `advertiser_url` | string | Link to all ads of the Page |
| `country` | string | Country filter applied to the request |
| `search_input` | string | Which input produced the ad: `query:X`, `page_id:X`, `advertiser:X` or `url:X` |
| `source_url` | string | The Ad Library URL used to fetch the ad |
| `scraped_at` | string | ISO 8601 UTC timestamp when the record was extracted |

### Pricing

Pay-per-result. An ad is charged only after it has been saved to the dataset, and each ad is charged once. A run with no results costs nothing.

| Event | When | Price |
|---|---|---|
| `actor-start` | Once per run, right before the first ads are saved | $0.005 |
| `facebook-ad-result` | Per ad saved to the dataset | $0.0008 |

Example: 1,000 ads cost one start event plus 1,000 ad events (about $0.81).

### Usage examples

#### Paste any Ad Library URL

```json
{
  "searchUrls": [
    "https://www.facebook.com/ads/library/?active_status=all&ad_type=all&country=DE&q=baulig&search_type=keyword_exact_phrase&publisher_platforms[0]=facebook&publisher_platforms[1]=instagram&start_date[min]=2025-06-06"
  ],
  "maxResults": 200,
  "maxAdsPerInput": 200
}
```

#### Search by keyword in a specific country

```json
{
  "searchQueries": ["Tesla Model 3", "electric vehicles"],
  "country": "US",
  "activeStatus": "ACTIVE",
  "mediaType": "VIDEO",
  "maxAdsPerInput": 100
}
```

#### Get all ads for a specific advertiser Page

```json
{
  "pageIds": ["15087023444"],
  "maxAdsPerInput": 500
}
```

#### Research political advertisers in the EU

```json
{
  "searchQueries": ["vote 2026", "election"],
  "adType": "POLITICAL_AND_ISSUE_ADS",
  "country": "DE",
  "contentLanguages": ["de"],
  "maxAdsPerInput": 200
}
```

#### Compare a brand across platforms

```json
{
  "advertiserNames": ["Nike"],
  "country": "ALL",
  "publisherPlatforms": ["facebook", "instagram"],
  "maxAdsPerInput": 500
}
```

#### EU ad transparency details (reach, targeting, payer)

```json
{
  "searchQueries": ["nike"],
  "country": "DE",
  "maxAdsPerInput": 20,
  "includeAdDetails": true
}
```

Example of the added fields for one ad:

```json
{
  "eu_total_reach": 140850,
  "targets_eu": true,
  "payer": "Example Media Ltd.",
  "beneficiary": "Example Media Ltd.",
  "target_ages": "21-65+",
  "target_gender": "All",
  "target_locations": ["Germany"],
  "reach_breakdown": [
    { "country": "DE", "age_range": "25-34", "male": 1200, "female": 800, "unknown": 12 }
  ],
  "ad_details_status": "ok"
}
```

### Use with AI agents (MCP)

Connect this actor to any MCP-compatible AI client, including Claude Desktop, Claude.ai, Cursor, VS Code, LangChain and LlamaIndex.

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

Example prompt: "Use `facebook-ad-library-scraper` to find 30 active Nike video ads in Germany, including page like count and call to action."

### Use cases

- **Competitive intelligence**: see what ads your competitors are running, with copy, creative and call to action
- **Creative research**: analyse ad hooks, CTAs and carousel structures at scale
- **Political ad transparency**: spend and reach ranges for political and issue ads
- **Market sizing**: measure category-level ad activity across countries and platforms
- **Lead generation**: find companies that advertise on Meta in your vertical
- **Compliance auditing**: surface AI-generated, sensitive or flagged ads

### Notes

- Meta's Ad Library is publicly accessible without login under their ad transparency policy
- Spend and reach ranges are Meta's own and only published for political and issue ads
- `collation_id` groups ad variants of one creative: group by it to see distinct creatives
- Meta serves 10 ads per page. The scraper waits about 1.5 seconds between requests, so 1,000 ads take roughly 3 minutes
- `pageIds` must be numeric Page IDs. To search by brand name use `advertiserNames`
- Meta limits how fast the Ad Library can be read. Blocked or rate-limited requests are retried automatically (`maxIPRotations`, default 5 retries). Large runs may need a higher value.
- Changes on Meta's side are handled automatically, so runs keep working without any action from you

### Data protection

This actor returns only data that is publicly visible on the source pages. Results can include personal data, such as names, phone numbers, email addresses and addresses of private persons, sole traders or contact persons. Where the source labels an entry type, it is included so you can filter the results yourself.

You are responsible for using the data lawfully, including the GDPR/DSGVO, national data-protection laws and unfair-competition rules (e.g. UWG) for marketing and outreach.

### Related actors

- [Instagram Scraper](https://apify.com/santamaria-automations/instagram-scraper) - profiles and posts of the brands you find in the Ad Library.
- [TikTok Search Scraper](https://apify.com/santamaria-automations/tiktok-search-scraper) - see the same brands' organic TikTok content.
- [Google Ads Transparency Scraper](https://apify.com/santamaria-automations/google-ads-scraper) - the Google side of a competitor's advertising.
- [Website Contact Extractor](https://apify.com/santamaria-automations/website-contact-extractor) - contact details from the advertisers' websites in `link_url`.

### Issues and feedback

- [Issues tab](https://apify.com/santamaria-automations/facebook-ad-library-scraper/issues) for bug reports and feature requests
- [More actors by santamaria-automations](https://apify.com/santamaria-automations)

# Actor input Schema

## `searchUrls` (type: `array`):

Paste any Facebook Ad Library URL - every filter in the URL (country, ad_type, active_status, media_type, publisher_platforms, content_languages, page_ids, start_date, search_type, sort_data) is auto-parsed. Easiest way to scrape: open Ad Library in your browser, apply filters, copy URL, paste here.

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

Keywords to search in the Meta Ad Library (e.g. 'Nike shoes', 'Tesla Model 3'). Each runs as a separate search. Results are deduplicated across all queries. If you give no searchUrls, searchQueries, pageIds or advertiserNames, the default keyword 'nike' is searched.

## `pageIds` (type: `array`):

Facebook Page IDs to fetch all ads for (numeric IDs, not usernames). Example: 15087023444 (Nike). Combine with searchQueries or use standalone.

## `advertiserNames` (type: `array`):

Brand/advertiser names - searched as exact phrases. Use this when you know the advertiser by name but not their Page ID.

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

ISO 3166-1 alpha-2 country code (e.g. 'US', 'GB', 'DE'). Use 'ALL' to search globally. Applied to searchQueries / pageIds / advertiserNames. Ignored when using searchUrls (URL takes precedence).

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

Type of ads to return.

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

Filter by whether the ad is currently running.

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

Filter by creative media format.

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

Restrict to ads running on specific Meta platforms.

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

ISO 639-1 language codes (e.g. 'en', 'de', 'es'). Returns only ads in these languages.

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

How keywords match ad text. 'Exact phrase' is stricter; 'Unordered' is broader.

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

Result ordering. Meta's Ad Library can sort by impressions or by time active (it has no newest-first sort). Impressions are only disclosed for political and issue ads; for other ads the default relevancy order is usually the most useful.

## `startDateMin` (type: `string`):

Only return ads that started running on or after this date (YYYY-MM-DD).

## `startDateMax` (type: `string`):

Only return ads that started running on or before this date (YYYY-MM-DD).

## `maxAdsPerInput` (type: `integer`):

Maximum ads per searchUrl / keyword / pageId / advertiser. Meta serves 10 ads per page.

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

Hard cap on total ads across all sources. Set to 0 for unlimited.

## `includeAdDetails` (type: `boolean`):

Add EU ad transparency details to every ad: total EU reach, reach by country, age and gender, targeting (ages, gender, locations), payer and beneficiary. Only ads delivered in the EU have reach and targeting data; other ads get the status not_eu. Makes the run slower because every ad needs one extra lookup.

## `maxIPRotations` (type: `integer`):

Meta rate-limits IPs on busy queries. On a rate limit the scraper starts a fresh session and retries. Default 5; increase up to 50 for high-volume runs, set 0 to disable.

## Actor input object example

```json
{
  "searchQueries": [
    "nike"
  ],
  "country": "ALL",
  "adType": "ALL",
  "activeStatus": "ALL",
  "mediaType": "ALL",
  "searchType": "keyword_unordered",
  "sortBy": "",
  "startDateMin": "2025-01-01",
  "startDateMax": "2025-12-31",
  "maxAdsPerInput": 20,
  "maxResults": 0,
  "includeAdDetails": false,
  "maxIPRotations": 5
}
```

# Actor output Schema

## `defaultDataset` (type: `string`):

Ads extracted from Meta's Ad Library - creative text, full snapshot (images/videos/cards), spend & reach bounds, publisher platforms, AAA/transparency data, advertiser lifetime spend, and EU/BR compliance fields.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": [
        "nike"
    ],
    "country": "ALL",
    "maxAdsPerInput": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/facebook-ad-library-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": ["nike"],
    "country": "ALL",
    "maxAdsPerInput": 20,
}

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

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

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

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "nike"
  ],
  "country": "ALL",
  "maxAdsPerInput": 20
}' |
apify call santamaria-automations/facebook-ad-library-scraper --silent --output-dataset

```

## MCP server setup

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

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

## OpenAPI specification

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