# Facebook Ads Library Scraper - Meta & Instagram Ads (`hgservices/facebook-ads-library-scraper`) Actor

Scrape the Facebook Ad Library by keyword, advertiser page or URL. Get ad copy, images, videos, CTAs, landing pages, platforms and run dates, plus spend, reach and sponsor of political ads. Filter by country, language, date and media. Export JSON, CSV or Excel.

- **URL**: https://apify.com/hgservices/facebook-ads-library-scraper.md
- **Developed by:** [Harish Garg](https://apify.com/hgservices) (community)
- **Stats:** 3 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

Scrape the **Facebook Ad Library** (Meta Ad Library) and get every ad that Facebook, Instagram, Messenger, Threads, WhatsApp and Audience Network show for a **keyword**, an **advertiser page** or an **Ad Library URL**. Get the ad copy, headline, call to action, landing page, **image and video URLs**, carousel cards, platforms and run dates for each ad. For political and issue ads, also get the **spend, impressions, reach and "Paid for by"** disclaimer.

Search any country, or all countries at once. Filter by ad status, category, media type, platform, language and date. Download the ads as JSON, CSV, Excel or HTML, or read them from the API.

No Facebook account. No login. No coding needed.

### What does Facebook Ads Library Scraper do?

- **Keyword search** — find ads that contain any of your words, or an exact phrase, the same as the Ad Library search box.
- **Advertiser search** — get all ads of one or more Facebook pages, for example every ad your competitor runs now.
- **Ad Library URLs** — paste a search you built on [facebook.com/ads/library](https://www.facebook.com/ads/library), and the scraper uses its filters.
- **Many searches in one run** — give a list of keywords, page IDs and URLs. Each one is a separate search, and each ad tells you which search found it.
- **Creatives** — image URLs, HD video URLs, video previews and every card of carousel and dynamic ads.
- **Political ad transparency** — spend range, impressions range, reach estimate and the "Paid for by" disclaimer that Meta publishes for political, election and issue ads.
- **Filters** — country (or all countries), active or inactive ads, ad category, media type (image, video, meme or text only), platform, language and the dates the ads were shown.

### Why scrape the Facebook Ad Library?

- **Competitor research** — see every ad a competitor runs, which creatives they keep running, and when they start a new campaign.
- **Creative inspiration and swipe files** — collect winning hooks, headlines, offers and calls to action in your niche before you spend money on tests.
- **E-commerce and dropshipping** — find products with ads that have run for months, a strong sign that they sell.
- **Agencies** — monitor the ads of all your clients and their competitors on a schedule, and report changes.
- **Political and election research** — track spend, reach and sponsors of political and issue ads, by country and by date.
- **Market and brand monitoring** — find out who advertises on your brand name or your keywords, in any country and language.
- **AI and data projects** — give fresh ad copy to an LLM to find angles, summarize campaigns or build a creative database.

### How to scrape the Facebook Ad Library

1. Open the scraper in Apify Console and click **Try for free**.
2. Enter one or more **Search keywords**, for example `nike` or `running shoes`. You can also enter **Advertiser page IDs** or paste **Ad Library URLs**.
3. Select the **Country**. Select **All countries** to search everywhere.
4. Set the optional filters: ad status, ad category, media type, platforms, languages, dates and sort order.
5. Set **Maximum ads per search**.
6. Click **Start**. The run log shows the progress of each search.
7. When the run finishes, open the **Output** tab, or download the ads as JSON, CSV, Excel or HTML.

#### How to find the page ID of an advertiser

Open the [Facebook Ad Library](https://www.facebook.com/ads/library), search for the advertiser and click its name. The URL of the page that opens contains `view_all_page_id=` followed by a number. That number is the page ID. You can also paste that whole URL into **Ad Library URLs**. Each ad in the output also has a `pageId`, so you can find all ads of an advertiser that an earlier keyword search found.

### Input

| Field | Description | Default |
|-------|-------------|---------|
| `searchQueries` | Keywords or advertiser names to search for. Each keyword is one search. | — |
| `pageIds` | Facebook page IDs of advertisers. Each page is one search. | — |
| `adLibraryUrls` | Search or advertiser URLs from facebook.com/ads/library. Each URL is one search. Filters in the URL are used; other filters come from the fields below. | — |
| `searchType` | `keyword` (any of the words) or `exact_phrase`. | `keyword` |
| `country` | Two-letter country code, for example `US`, `GB`, `DE`, `IN`, or `ALL` for all countries. | `US` |
| `activeStatus` | `active`, `inactive` or `all`. | `active` |
| `adType` | `all`, `political_and_issue_ads`, `housing_ads`, `employment_ads` or `financial_products_and_services_ads`. | `all` |
| `mediaType` | `all`, `image`, `video`, `meme` or `none` (text only). | `all` |
| `platforms` | Any of `facebook`, `instagram`, `messenger`, `audience_network`, `threads`, `whatsapp`. Empty means all platforms. | all |
| `languages` | Two-letter language codes, for example `en`, `es`, `de`, `ja`. Empty means all languages. | all |
| `dateFrom`, `dateTo` | Get only ads that were shown in this date range (`YYYY-MM-DD`). | — |
| `sortBy` | `impressions` (most impressions first) or `newest`. | `impressions` |
| `maxAdsPerSearch` | Maximum number of ads for each search (1 to 100,000). | `100` |

You must give at least one keyword, page ID or URL.

#### Input examples

All active ads of two advertisers (Nike and Foot Locker) in the United States, newest first:

```json
{
    "pageIds": ["15087023444", "67997232685"],
    "country": "US",
    "sortBy": "newest",
    "maxAdsPerSearch": 500
}
```

Video ads in Spanish that mention an exact phrase in Mexico, shown in September 2026:

```json
{
    "searchQueries": ["envío gratis"],
    "searchType": "exact_phrase",
    "country": "MX",
    "mediaType": "video",
    "languages": ["es"],
    "activeStatus": "all",
    "dateFrom": "2026-09-01",
    "dateTo": "2026-09-30"
}
```

Political ads about an election, with spend and reach:

```json
{
    "searchQueries": ["election", "vote"],
    "country": "US",
    "adType": "political_and_issue_ads",
    "activeStatus": "all",
    "maxAdsPerSearch": 1000
}
```

### Output

Each ad is one item in the dataset. This is a shortened example:

```json
{
    "adArchiveId": "2958021017868670",
    "snapshotUrl": "https://www.facebook.com/ads/library/?id=2958021017868670",
    "pageId": "112036763854033",
    "pageName": "Friends of Sunset Dunes",
    "pageProfileUri": "https://www.facebook.com/friendsofoceanbeachpark/",
    "isActive": true,
    "startDate": "2026-09-18T07:00:00.000Z",
    "endDate": "2026-10-04T07:00:00.000Z",
    "platforms": ["FACEBOOK", "INSTAGRAM"],
    "categories": ["POLITICAL"],
    "bodyText": "Proposition G would destroy Sunset Dunes...",
    "title": "Vote NO on G to Save Sunset Dunes Park",
    "ctaText": "Learn more",
    "ctaType": "LEARN_MORE",
    "linkUrl": "https://savesunsetdunes.org/",
    "displayFormat": "DCO",
    "imageCount": 0,
    "videoCount": 4,
    "cardCount": 4,
    "imageUrls": [],
    "videoUrls": ["https://video.xx.fbcdn.net/..."],
    "videoPreviewImageUrls": ["https://scontent.xx.fbcdn.net/..."],
    "cards": [
        {
            "title": "Vote NO on G to Save Sunset Dunes Park",
            "body": "Proposition G would destroy Sunset Dunes...",
            "linkUrl": "https://savesunsetdunes.org/",
            "ctaText": "Learn more",
            "imageUrl": null,
            "videoUrl": "https://video.xx.fbcdn.net/..."
        }
    ],
    "pageLikeCount": 1541,
    "paidForBy": "No on G, Save Sunset Dunes Park, sponsored by Friends of Sunset Dunes",
    "spend": "$8K-$9K",
    "currency": "USD",
    "impressionsText": ">1M",
    "reachEstimate": "500K-1M",
    "containsAiContent": false,
    "searchTerm": "vote",
    "searchType": "keyword",
    "searchCountry": "US",
    "searchUrl": "https://www.facebook.com/ads/library/?active_status=active&ad_type=political_and_issue_ads&country=US&media_type=all&q=vote&search_type=keyword_unordered",
    "scrapedAt": "2026-10-04T13:01:56.000Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. The **Output** tab has three views: **Ads** (copy, CTA and dates), **Creatives** (images, videos and cards) and **Spend and reach** (political and regulated ads).

#### Output fields

| Field | Description |
|-------|-------------|
| `adArchiveId`, `snapshotUrl` | Ad Library ID of the ad and the public link that shows it |
| `pageId`, `pageName`, `pageProfileUri`, `pageProfilePictureUrl` | The advertiser page |
| `isActive`, `startDate`, `endDate` | Status and run dates. For an active ad, `endDate` is the most recent day |
| `platforms` | Where the ad runs: Facebook, Instagram, Messenger, Threads, WhatsApp, Audience Network |
| `bodyText`, `title`, `caption`, `linkDescription` | The ad copy |
| `ctaText`, `ctaType`, `linkUrl` | Call to action and landing page |
| `displayFormat` | Image, video, carousel, dynamic (DCO), catalog (DPA) or text |
| `imageUrls`, `videoUrls`, `videoPreviewImageUrls`, `cards` | The creative: media links and carousel cards |
| `imageCount`, `videoCount`, `cardCount` | Number of images, videos and cards |
| `collationCount` | Number of ads that use the same creative |
| `pageLikeCount`, `pageCategories` | Size and category of the advertiser page |
| `categories` | Ad Library categories, for example `POLITICAL` or `EMPLOYMENT` |
| `paidForBy`, `spend`, `currency`, `impressionsText`, `reachEstimate` | Transparency data. Meta publishes it for political and issue ads, and reach for some other regulated ads |
| `containsAiContent` | Meta labels the creative as AI-generated or digitally created |
| `searchTerm`, `searchType`, `searchCountry`, `searchUrl` | The search that found the ad |
| `scrapedAt` | When the run collected the ad |

#### Run summary

Each run also saves a `SUMMARY` record in the key-value store. It shows the number of ads and the result of each search, for example `max_ads` (the limit was reached), `end_of_results` (all ads were collected), `no_results` or `charge_limit` (the run reached your maximum cost per run).

### How much does it cost to scrape the Facebook Ad Library?

The scraper uses **pay-per-event** pricing, so you pay only for what you get:

| Event | When it is charged |
|---|---|
| `search` | Once per run, when the run starts |
| `result` | Once for each ad saved to the dataset |

See the **Pricing** tab for the current prices. Set a **maximum cost per run** in the run options to cap the bill: the scraper stops when it reaches the limit and keeps every ad collected so far.

### Use the scraper with the Apify API

You can run the scraper and read the ads from any programming language with the [Apify API](https://docs.apify.com/api/v2). Get your API token in Apify Console under **Settings → API & Integrations**, and replace `<YOUR_API_TOKEN>` below.

**HTTP (cURL)** — run the scraper and get the ads in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/hgservices~facebook-ads-library-scraper/run-sync-get-dataset-items?format=json" \
  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "searchQueries": ["running shoes"], "country": "US", "maxAdsPerSearch": 50 }'
```

Change `format=json` to `format=csv` or `format=xlsx` to get a spreadsheet. For runs that take longer than 5 minutes, start the run with `POST /v2/acts/hgservices~facebook-ads-library-scraper/runs` and read the dataset when it finishes.

**JavaScript / Node.js**

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });

const run = await client.actor('hgservices/facebook-ads-library-scraper').call({
    searchQueries: ['running shoes', 'protein powder'],
    country: 'GB',
    mediaType: 'video',
    maxAdsPerSearch: 100,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const ad of items) {
    console.log(ad.pageName, ad.startDate.slice(0, 10), ad.title, ad.videoUrls[0]);
}
```

**Python** (`apify-client` 3.0 or later)

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")

run = client.actor("hgservices/facebook-ads-library-scraper").call(run_input={
    "pageIds": ["15087023444"],
    "country": "ALL",
    "activeStatus": "all",
    "maxAdsPerSearch": 500,
})
if run is None:
    raise RuntimeError("The run was not found.")

for ad in client.dataset(run.default_dataset_id).iterate_items():
    print(ad["startDate"][:10], ad["displayFormat"], ad["bodyText"])
```

### Use Facebook ads data in Claude, ChatGPT and other AI assistants

This scraper works as a tool for AI assistants through the [Apify MCP server](https://mcp.apify.com/). Your assistant can find the scraper, read its input options, run it and use the ads in its answer.

**Claude (claude.ai or Claude Desktop)** — Go to **Settings → Connectors**, add a custom connector, and enter `https://mcp.apify.com`. Sign in to Apify when Claude asks.

**Claude Code**

```bash
claude mcp add --transport http apify https://mcp.apify.com
```

**ChatGPT** — Turn on **Developer mode** in **Settings → Apps & Connectors → Advanced settings**. Then create a connector with the MCP server URL `https://mcp.apify.com`.

**Cursor, VS Code and other MCP clients** — Add `https://mcp.apify.com` as a remote MCP server. To give the assistant only this scraper, use `https://mcp.apify.com?tools=hgservices/facebook-ads-library-scraper`.

Then ask in plain language:

> Use the Facebook Ads Library Scraper to get the 50 newest active ads of Nike in the US, and summarize the main offers and hooks.

> Find video ads in Germany that mention "Schuhe", and list the advertisers that run the most ads.

> Get political ads about "vote" in the US and make a table of sponsors, spend and reach.

For the best results, tell the assistant the keywords or the advertiser, the country and the number of ads. This keeps the run fast and the cost low.

### Integrations and scheduling

Connect the scraper to the tools you already use with [Apify integrations](https://apify.com/integrations): **Google Sheets, Slack, Zapier, Make, n8n, Airbyte, Keboola** and more. Use **webhooks** to call your own endpoint when a run finishes.

Use **Schedules** in Apify Console to monitor ads automatically. For example, run a search for your competitors' page IDs every morning with `sortBy: "newest"`, and compare the `adArchiveId` values with the previous day to find new ads.

### Tips

- **Advertiser searches are the most precise.** A keyword search also finds ads that only mention the word. Use `pageIds` to get only the ads of one advertiser.
- **Use "Newest first"** with a small `maxAdsPerSearch` to monitor new ads quickly and at a low cost.
- **Spend and reach data** exist only for political, election and issue ads (and reach for some other regulated categories). Set `adType` to `political_and_issue_ads` to get them. Commercial ads have no spend data in the Ad Library.
- **Download media soon.** Image and video URLs are temporary Facebook links that stop working after a few days.
- **Dates** filter the days on which the ads were shown, not only the day they started.
- **Broaden a search with no results**: use `ALL` countries, `activeStatus: "all"`, or fewer filters.

### FAQ

**Is it legal to scrape the Facebook Ad Library?**
The Ad Library is a public transparency database that Meta publishes for everyone. This scraper collects only that public data, and it does not log in to Facebook. You are responsible for how you use the data, including compliance with Meta's terms and with data protection laws such as GDPR. If you are not sure, ask a lawyer.

**Do I need a Facebook account or the Meta Ad Library API?**
No. The scraper needs no account, no access token and no identity check.

**How many ads can I get?**
Up to 100,000 ads for each search, and up to 1,000 searches in one run. The scraper removes duplicate ads within each search. If two searches find the same ad, each search returns it, with its own `searchTerm`.

**Why did my search return fewer ads than the Ad Library website shows?**
The number on the website is an estimate. Also check the filters: the scraper uses the country, status and media type of your input.

**Why do some ads have `{{product.name}}`-style text?**
Some catalog ads fill in the text for each viewer. The scraper uses the text of the first card when the main text is a template. When no card has text, the template stays.

**Can I scrape a single ad by its ID?**
Use the advertiser's page ID or a keyword. A URL that shows only one ad (`?id=...`) is not a search.

### Support

Found a bug or need a new field? Open an issue in the **Issues** tab. For a custom solution, such as a scheduled pipeline into your database, contact the author through Apify.

# Actor input Schema

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

Keywords or advertiser names to search for, the same as the Ad Library search box. Each keyword is one search.

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

Facebook page IDs of advertisers, to get all ads of each page. Find the ID in the Ad Library URL of the advertiser (view_all_page_id=...) or in the pageId field of earlier results. Each page is one search.

## `adLibraryUrls` (type: `array`):

Search or advertiser URLs copied from facebook.com/ads/library. Each URL is one search. Filters in the URL are used; filters that the URL does not set come from the fields below.

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

How keywords match the ads. "Exact phrase" finds ads that contain the keywords in this order.

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

Country where the ads were shown. Select "All countries" to search everywhere.

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

Get ads that are running now, ads that stopped, or both.

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

Ad category. Spend, impressions and reach are available only for the special categories, mainly political and issue ads.

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

Type of media in the ad.

## `platforms` (type: `array`):

Get only ads that ran on these platforms. Leave empty for all platforms.

## `languages` (type: `array`):

Get only ads in these languages. Leave empty for all languages.

## `dateFrom` (type: `string`):

Get only ads that were shown on or after this date (YYYY-MM-DD).

## `dateTo` (type: `string`):

Get only ads that were shown on or before this date (YYYY-MM-DD).

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

Order of the ads. With a limit on the number of ads, this decides which ads you get.

## `maxAdsPerSearch` (type: `integer`):

Stop each search after this many ads.

## Actor input object example

```json
{
  "searchQueries": [
    "nike"
  ],
  "searchType": "keyword",
  "country": "US",
  "activeStatus": "active",
  "adType": "all",
  "mediaType": "all",
  "sortBy": "impressions",
  "maxAdsPerSearch": 100
}
```

# Actor output Schema

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

No description

## `creatives` (type: `string`):

No description

## `spend` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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": "US",
    "maxAdsPerSearch": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("hgservices/facebook-ads-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": "US",
    "maxAdsPerSearch": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("hgservices/facebook-ads-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": "US",
  "maxAdsPerSearch": 100
}' |
apify call hgservices/facebook-ads-library-scraper --silent --output-dataset

```

## MCP server setup

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