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

Scrape ads from the public Facebook Ad Library by keyword, advertiser page and country: ad text, CTA, landing URL, images, videos, run dates and platforms. No login or cookies. Pay only for ads returned.

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

## Pricing

from $4.00 / 1,000 ads

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/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

### What does Facebook Ad Library Scraper do?

Facebook Ad Library Scraper collects ads from the public [Meta Ad Library](https://www.facebook.com/ads/library/), the transparency site where Meta lists ads that run on Facebook, Instagram, Messenger, Threads, WhatsApp and the Audience Network. Search by keyword, by advertiser page id, or paste Ad Library search URLs, and filter by country, active or inactive status, ad category and media type. For every ad you get the advertiser page and its link, the run dates, the platforms it ran on, the ad text, headline, link description, call to action, the landing URL and the image and video URLs, plus how many versions of the ad exist. For political and issue ads, you also get the spend range, impressions range, reach and who paid for the ad when Facebook shows them. It works without a Facebook account, cookies or API token. Use it for competitor ad research, creative inspiration, market research and lists of brands that advertise on Meta.

### How to use it

1. Add one or more keywords (for example `running shoes`), advertiser page ids, or Ad Library URLs.
2. Pick a country and, if you like, active status, ad category and media type.
3. Set **Max ads per search** and start the run.
4. Download the ads as JSON, CSV, Excel or HTML, or read them through the Apify API.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `searchQueries` | array of strings | | Keywords, as typed in the Ad Library search box. Each keyword is one search. |
| `pageIds` | array of strings | | Numeric Facebook page ids. Each returns that advertiser's ads (the Ad Library `view_all_page_id` view). |
| `startUrls` | array of URLs | | Ad Library search URLs with `q` or `view_all_page_id`. Their country and filters are kept. Other URLs are skipped. |
| `country` | string | `US` | Two letter ISO code such as `US`, `GB`, `DE`, or `ALL`. |
| `activeStatus` | string | `all` | `all`, `active` or `inactive`. |
| `adType` | string | `all` | `all`, `political_and_issue_ads`, `housing_ads`, `employment_ads`, `credit_ads` or `financial_products_and_services_ads`. |
| `mediaType` | string | `all` | `all`, `image`, `video`, `meme`, `image_and_meme` or `none`. |
| `maxAdsPerQuery` | integer | 50 | Maximum ads per keyword, page id or URL. |
| `maxConcurrency` | integer | 3 | Searches run at the same time. |
| `maxRequestRetries` | integer | 6 | Attempts per search, each on a new proxy IP. A retry continues where the last one stopped. |
| `proxy` | object | Residential | Proxy settings. Residential proxies are recommended. |

#### Input example

```json
{
  "searchQueries": ["running shoes"],
  "pageIds": ["20662169998"],
  "startUrls": [
    { "url": "https://www.facebook.com/ads/library/?active_status=inactive&ad_type=all&country=US&q=protein%20powder&search_type=keyword_unordered&media_type=all" }
  ],
  "country": "US",
  "activeStatus": "all",
  "adType": "all",
  "mediaType": "all",
  "maxAdsPerQuery": 60,
  "proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

### Output

One dataset item per ad. This item is from a real local run (search `protein powder`, inactive ads, country US). Long CDN query strings are shortened with `...`.

```json
{
  "adArchiveId": "3683258205282107",
  "adUrl": "https://www.facebook.com/ads/library/?id=3683258205282107",
  "pageId": "102964152719743",
  "pageName": "Wellcore - Wellversed Brand",
  "pageUrl": "https://www.facebook.com/100090438782097/",
  "pageProfilePicture": "https://scontent.flhe39-1.fna.fbcdn.net/v/t39.35426-6/410769028_1763995944026267_2344153979246753343_n.jpg?...",
  "isActive": false,
  "startDate": "2023-12-14T08:00:00.000Z",
  "endDate": "2026-02-03T08:00:00.000Z",
  "platforms": ["facebook", "instagram", "audience_network"],
  "format": "VIDEO",
  "adText": "Step Beyond the Ordinary: Embrace the Next-Generation Energy Formula to Surpass All Limits.",
  "title": null,
  "linkDescription": null,
  "cta": null,
  "landingUrl": null,
  "media": [
    {
      "type": "video",
      "url": "https://video.flhe39-1.fna.fbcdn.net/o1/v/t2/f2/m560/AQPSX-2UlapsHNvHMmDBN7p1P45V1jEnVBRLwlXhVx_Gx-lha6nF-h9gZo-VYZgFilWZjLaF0ztk8F9-AneOolEGkZ8AN7WNuvk.mp4?...",
      "previewImageUrl": "https://scontent.flhe39-1.fna.fbcdn.net/v/t39.35426-6/410784844_322318904009450_6190459882608289908_n.jpg?..."
    }
  ],
  "collationCount": 1,
  "paidBy": null,
  "disclaimer": null,
  "searchQuery": "protein powder",
  "scrapedAt": "2026-10-17T17:43:13.395Z"
}
```

#### Output fields

| Field | Description |
| --- | --- |
| `adArchiveId`, `adUrl` | Ad Library id and the public link to the ad. |
| `pageId`, `pageName`, `pageUrl`, `pageProfilePicture` | The advertiser's Facebook page. |
| `isActive`, `startDate`, `endDate` | Status and run dates in ISO format. For active ads `endDate` is the latest day Facebook reports. |
| `platforms` | Where the ad ran: `facebook`, `instagram`, `audience_network`, `messenger`, `threads`, `whatsapp`. |
| `format` | Facebook's display format: `IMAGE`, `VIDEO`, `CAROUSEL`, `DCO`, `DPA` and others. |
| `adText`, `title`, `linkDescription`, `cta` | Ad copy. For catalog ads with `{{product.name}}` style templates, the first real card is used. |
| `landingUrl` | Destination link, with `l.facebook.com` redirects removed. |
| `media` | Images and videos: `{ type, url }`, plus `previewImageUrl` for videos. Carousel and catalog cards are included. |
| `collationCount` | Number of versions of this ad, when Facebook groups them. |
| `paidBy`, `disclaimer` | "Paid for by" text and label, mostly on political and issue ads. |
| `spend`, `currency`, `impressions`, `reachEstimate` | Only present when Facebook shows them, which is mainly political and issue ads. |
| `searchQuery`, `scrapedAt` | The keyword or page id that found the ad, and when it was scraped. |

### Pricing

$4 per 1,000 ads returned. An ad found by more than one of your searches in the same run is returned and charged once. Searches that fail are not charged.

### FAQ

#### Do I need a Facebook account or API token?

No. The scraper opens the public Ad Library as a logged-out visitor. It uses no Facebook login, no account cookies and no Ad Library API token.

#### Which countries can I search?

Any country the Ad Library offers, by its two letter ISO code (for example `US`, `GB`, `DE`, `BR`), or `ALL` for every country. Each search uses one country.

#### Can I see ad spend?

Only for political and issue ads (and other ads where Facebook shows it to logged-out visitors). For those ads you get the spend range, currency, impressions range, estimated reach and who paid. Facebook does not show spend for regular commercial ads, so the scraper cannot return it.

#### How do I find a page id?

Open the advertiser in the Ad Library and click "See all ads". The number after `view_all_page_id=` in the address bar is the page id. You can also paste that whole URL into **Ad Library URLs**.

#### Why do I get fewer ads than the maximum?

The Ad Library shows a limited list for each search, and some searches simply have fewer matching ads. The run log and the `FAILED_ITEMS` record in the key-value store say why a search stopped.

#### Is there a LinkedIn version?

Yes. [LinkedIn Ad Library Scraper](https://apify.com/muhammad_noman_riaz/linkedin-ad-library-scraper) returns ads from LinkedIn's public Ad Library with matching field names such as `adUrl`, `adText`, `cta` and `landingUrl`, so you can compare both channels side by side.

### Known limits

- Demographic and regional breakdowns of political ads are not included. Facebook shows them only in each ad's detail view, which this scraper does not open.
- Plain facebook.com page URLs (for example `https://www.facebook.com/Saucony/`) are not resolved to page ids. Use the page id or the Ad Library "See all ads" URL.
- Single ad URLs (`/ads/library/?id=...`) are not supported as input.
- Facebook loads the Ad Library through a small browser check, so the scraper runs a real Chrome browser with images, styles and scripts blocked. It is slower than plain HTTP scrapers.
- If Facebook asks for a captcha or shows a login wall, that attempt is dropped and retried on a new proxy IP. The scraper never solves captchas.
- Media URLs are signed Facebook CDN links that expire after some days. Download the files soon after the run if you need them.
- Facebook can change the Ad Library at any time, which may break the scraper until it is updated.

# Actor input Schema

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

Keywords to search in the Ad Library, as you would type them in its search box. Each keyword is a separate search.

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

Numeric Facebook page ids. Returns the ads of each page, like the Ad Library 'See all ads' view (view_all_page_id).

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

Ad Library search URLs (https://www.facebook.com/ads/library/?...) with a q keyword or a view_all_page_id. Their country, active status, ad type and media type filters are kept. Other URLs are skipped.

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

Two letter ISO country code where the ads ran, for example US, GB or DE. Use ALL for all countries.

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

Return active ads, inactive ads or both.

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

Ad Library category. Political and issue ads include spend and impressions when Facebook shows them.

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

Only return ads with this kind of media.

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

Maximum number of ads to return for each keyword, page id and URL.

## `maxConcurrency` (type: `integer`):

Maximum number of searches run at the same time.

## `maxRequestRetries` (type: `integer`):

How many times a search is tried, each time on a new proxy IP, before it is stopped. A retry continues where the last attempt stopped.

## `proxy` (type: `object`):

Proxy used for requests. Residential proxies are recommended because Facebook rate limits datacenter IPs.

## Actor input object example

```json
{
  "searchQueries": [
    "running shoes"
  ],
  "country": "US",
  "activeStatus": "all",
  "adType": "all",
  "mediaType": "all",
  "maxAdsPerQuery": 50,
  "maxConcurrency": 3,
  "maxRequestRetries": 6,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `ads` (type: `string`):

One item per ad with advertiser page, run dates, platforms, ad text, CTA, landing URL and media

# 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": [
        "running shoes"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammad_noman_riaz/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": ["running shoes"],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

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

```

## MCP server setup

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