# Facebook Ads Library Scraper (Meta Ad Library) (`pulsedata/facebook-ad-library-scraper`) Actor

Facebook Ads Library scraper for the Meta Ad Library. Export Facebook, Instagram and Messenger ads by keyword, advertiser page ID or Ad Library URL: ad text, images, videos, links, run dates and platforms. No login needed.

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

## Pricing

from $3.00 / 1,000 ad scrapeds

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

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 Ads Library Scraper (Meta Ad Library)

This actor exports ads from the [Meta Ad Library](https://www.facebook.com/ads/library/) for Facebook, Instagram, Messenger, Threads and Audience Network. You search by keyword, by advertiser page ID, or by pasting an Ad Library search URL, and get one JSON row per ad with the ad text, headline, link, call to action, image and video URLs, carousel cards, start and end date, the platforms it ran on and the advertiser page. It costs $3.00 per 1,000 ads plus $0.01 per run.

The actor works logged out, the same way the public Ad Library page does. It needs no Facebook account, no cookies and no Meta API token.

### Features

- **Scrape all Facebook ads of an advertiser** by numeric page ID, active and inactive.
- **Search the Meta Ad Library by keyword** in one country or all countries. Wrap the keyword in double quotes for the exact phrase.
- **Scrape a Facebook Ad Library URL** you set up in the browser. The filters in the URL are used as they are.
- **Filter Facebook ads by country, status and media type**: active or inactive, images, videos, memes or text only.
- **Export political and issue ads with spend and impressions ranges**, plus the "paid for by" disclaimer.
- **Search housing, employment and credit ads**, the special ad categories Meta files separately.
- **Export Meta Ad Library data to CSV, Excel or JSON** through the Apify dataset.

### Use cases

- **Competitor ad research**: every creative a competitor runs on Facebook and Instagram, when each ad started, and whether it is still live. Ads that have been running for months are usually the ones that convert.
- **Creative and copy research**: ad text, headlines, calls to action and media URLs for a swipe file, or as input for an LLM that groups ads by angle or offer.
- **Agency pitches and audits**: bring a prospect's current Meta ads and run dates to the first meeting.
- **Market scans by country**: which brands advertise a product category in Germany, France or the US right now.
- **Political ad monitoring**: spend and impression ranges and the paying entity for political and issue ads.
- **Lead generation**: check which companies advertise on Meta at all. Pass a list of page IDs and set `maxAdsPerQuery` to 1.

### Input

| Field | What it does |
|---|---|
| `queries` (required) | One search per line. A keyword such as `running shoes`, `"running shoes"` for the exact phrase, a numeric page ID such as `15087023444` for every ad of one advertiser, or a URL copied from facebook.com/ads/library. |
| `country` | ISO code (`US`, `DE`, `GB`), a country name such as `Germany`, or `ALL`. Default `ALL`. |
| `activeStatus` | `all` (default), `active` or `inactive`. |
| `mediaType` | `all` (default), `image`, `video`, `meme` or `none` (text only). |
| `adType` | `all` (default), `political_and_issue_ads`, `housing_ads`, `employment_ads` or `credit_ads`. |
| `maxAdsPerQuery` | Stop after this many ads per line. Default 100, `0` for no limit. |
| `proxyConfiguration` | Residential Apify Proxy by default. Leave it as is; Meta keeps datacenter IPs on its challenge page. |

Example input:

```json
{
  "queries": ["nike", "\"running shoes\"", "15087023444"],
  "country": "US",
  "activeStatus": "active",
  "mediaType": "all",
  "adType": "all",
  "maxAdsPerQuery": 200
}
```

A pasted Ad Library URL keeps its own filters. For example `https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=FR&q=decathlon&search_type=keyword_unordered&media_type=video` returns active video ads for "decathlon" in France, whatever the country and media type fields say. URLs with `view_all_page_id=` return every ad of that advertiser.

#### How to find a page ID

Facebook page names and vanity URLs such as `facebook.com/nike` cannot be resolved without logging in, so an advertiser search needs the numeric page ID. Open the advertiser in the Ad Library in your browser and copy the number after `view_all_page_id=` in the address bar, or read it from the page's transparency section. Lines the actor cannot use are skipped with a note in the log, and the other lines still run.

### Output

One item per ad:

```json
{
  "query": "adidas",
  "country": "GB",
  "adArchiveId": "1654579272491885",
  "adLibraryUrl": "https://www.facebook.com/ads/library/?id=1654579272491885",
  "pageId": "182162001806727",
  "pageName": "adidas",
  "pageUrl": "https://www.facebook.com/adidas/",
  "pageLikeCount": 43588716,
  "pageCategories": ["Product/service"],
  "isActive": true,
  "startDate": "2026-05-21",
  "endDate": "2026-09-26",
  "daysActive": 128,
  "publisherPlatforms": ["FACEBOOK", "INSTAGRAM"],
  "displayFormat": "DPA",
  "title": "Copa Mundial",
  "body": "Refresh your wardrobe with adidas icons.",
  "linkUrl": "https://www.adidas.co.uk/",
  "ctaText": "Shop now",
  "ctaType": "SHOP_NOW",
  "imageUrls": [],
  "videos": [],
  "cards": [
    {
      "title": "Copa Mundial Boots",
      "linkUrl": "https://www.adidas.co.uk/copa-mundial-boots/015110.html",
      "imageUrl": "https://scontent..."
    }
  ],
  "collationCount": null,
  "categories": ["UNKNOWN"],
  "disclaimer": null,
  "spend": null,
  "impressions": null,
  "currency": null,
  "reachEstimate": null,
  "scrapedAt": "2026-09-26T17:10:00.000Z"
}
```

For a political ad in the US, the same row carries the ranges Meta publishes:

```json
{
  "categories": ["POLITICAL"],
  "disclaimer": "Facebook, Inc.",
  "spend": ">$1M",
  "impressions": ">1M",
  "currency": "USD",
  "reachEstimate": ">1M"
}
```

Items also include `caption`, `linkDescription`, `pageProfilePictureUrl`, `collationId`, `targetedOrReachedCountries` and `containsSensitiveContent`. Each video has `hdUrl`, `sdUrl` and `previewImageUrl`; each carousel card has its own text, link, call to action and media. `collationCount` is the number of near-identical versions Meta groups under one ad.

### What Meta publishes

Meta shows the creative, the advertiser and the run dates for every ad in the library. Spend, impressions and reach are published as ranges for political and issue ads, and those are the only ads where these fields are usually filled. For ordinary commercial ads they come back as `null`. The actor reads the Ad Library search results and does not open each ad's detail page, so the EU reach and targeting breakdown Meta shows there is not included.

### Pricing

| Event | Price |
|---|---|
| `ad-scraped`, per ad returned | $0.003 |
| `apify-actor-start`, per run | $0.01 |

That is $3.00 per 1,000 ads plus $0.01 per run. Worked example: 300 active Nike ads in the US cost 300 × $0.003 + $0.01 = $0.91. A search that finds no ads costs only the $0.01 start.

If you set a maximum cost per run in the run options, the actor stops cleanly at that amount and keeps everything collected up to that point, so the dataset is never lost to a budget abort.

### FAQ

**Do I need a Facebook account or a Meta API token?**
No. The actor reads the public Ad Library logged out. It never logs in and cannot see anything a logged-out visitor cannot see.

**Why is my search by page name skipped?**
Page names and URLs like `facebook.com/somebrand` only resolve to an advertiser when you are logged in. Use the numeric page ID or an Ad Library URL with `view_all_page_id=`. See "How to find a page ID" above.

**Can I get all ads of an advertiser, not just 100?**
Set `maxAdsPerQuery` to `0`. The actor follows the Ad Library's own pagination until the last page. Large advertisers have thousands of ads and each one is charged, so set a maximum cost per run.

**How fast is it?**
In our test runs 50 to 300 ads took 20 to 80 seconds, and 1,200 ads of one advertiser took about 15 minutes. All searches in one run share a single browser session.

**How long do the image and video links work?**
Meta signs media URLs and they expire after some days. Download the files soon after the run if you need them.

**Does the country filter mean the ad targeted that country?**
It means the ad was shown there, as in the Ad Library's own country filter. `ALL` searches every country.

**How current is the data?**
Each run reads the Ad Library live at that moment.

**Can I schedule it or use it via API?**
Yes. Save a task with your queries, add an Apify schedule, and pull the dataset as JSON, CSV or Excel through the API, or send it to Google Sheets, Make, Zapier or n8n.

**What can it not do?**
It does not return clicks, conversions, audience targeting or the EU reach breakdown from ad detail pages, and it does not download media files. Spend and impressions are ranges, and only where Meta publishes them.

**Is it legal to use this data?**
The actor returns public ad data only. If you process ads from individuals or political "paid for by" disclaimers, you are responsible for handling that personal data lawfully, for example under the GDPR.

### Example pages

- [Export every ad a Facebook page has run](https://apify.com/pulsedata/facebook-ad-library-scraper/examples/facebook-ads-by-page-id)
- [Nike ads in the Facebook Ad Library in the US](https://apify.com/pulsedata/facebook-ad-library-scraper/examples/nike-facebook-ads-us)
- [Active adidas ads on Facebook and Instagram in the UK](https://apify.com/pulsedata/facebook-ad-library-scraper/examples/adidas-facebook-ads-uk)
- [US political ads about the election with spend and impressions](https://apify.com/pulsedata/facebook-ad-library-scraper/examples/us-political-ads-spend)
- [Video ads for running shoes shown in Germany](https://apify.com/pulsedata/facebook-ad-library-scraper/examples/running-shoes-video-ads-germany)
- [Scrape a Meta Ad Library search URL](https://apify.com/pulsedata/facebook-ad-library-scraper/examples/ad-library-url-export)
- [Find the Facebook ads an advertiser has stopped running](https://apify.com/pulsedata/facebook-ad-library-scraper/examples/stopped-facebook-ads)
- [Job ads in the Meta Ad Library in the US](https://apify.com/pulsedata/facebook-ad-library-scraper/examples/facebook-job-ads-us)
- [Loan and credit ads on Facebook in the US](https://apify.com/pulsedata/facebook-ad-library-scraper/examples/loan-ads-us-credit)
- [Temu ads on Facebook and Instagram in Germany](https://apify.com/pulsedata/facebook-ad-library-scraper/examples/temu-facebook-ads-germany)

### Related actors

- [Google Ads Transparency Center Scraper](https://apify.com/pulsedata/google-ads-transparency-scraper): the same competitor view for Google Search, YouTube, Shopping, Maps and Play ads.
- [LinkedIn Ad Library Scraper](https://apify.com/pulsedata/linkedin-ad-library-scraper): B2B ads with impressions per country and targeting for EU ads.
- [TikTok Ad Library Scraper](https://apify.com/pulsedata/tiktok-ad-library-scraper): TikTok video ads shown in Europe, with run dates and audience size.
- [Website Tech Stack Detector](https://apify.com/pulsedata/website-tech-stack-detector): what an advertiser's landing pages are built with.

# Actor input Schema

## `queries` (type: `array`):

One search per line. A keyword such as `running shoes` (wrap it in double quotes for the exact phrase), a numeric Facebook page ID such as `15087023444` for every ad of one advertiser, or a URL copied from facebook.com/ads/library. Filters inside a pasted URL override the filters below.

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

Where the ads were shown: an ISO code such as `US`, `DE` or `GB`, a country name, or `ALL`.

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

Only ads that are running now, only ads that stopped, or both.

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

Filter by the ad's creative.

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

All ads, or only one of the special categories Meta files separately.

## `maxAdsPerQuery` (type: `integer`):

Stop after this many ads per line of input. 0 means no limit.

## `proxyConfiguration` (type: `object`):

Meta keeps datacenter browsers on its challenge page, so this actor uses residential proxies by default.

## `debugDump` (type: `boolean`):

Stores a screenshot and the page HTML in the run's key-value store. Only needed when reporting a problem.

## Actor input object example

```json
{
  "queries": [
    "Nike"
  ],
  "country": "ALL",
  "activeStatus": "all",
  "mediaType": "all",
  "adType": "all",
  "maxAdsPerQuery": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "debugDump": false
}
```

# Actor output Schema

## `results` (type: `string`):

Meta ads stored in the default dataset.

# 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 = {
    "queries": [
        "Nike"
    ],
    "country": "ALL",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("pulsedata/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 = {
    "queries": ["Nike"],
    "country": "ALL",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("pulsedata/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 '{
  "queries": [
    "Nike"
  ],
  "country": "ALL",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call pulsedata/facebook-ad-library-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pulsedata/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/XFZjmjVt2wVopLbEX/builds/Vs9Urhpalfqft7P2F/openapi.json
