# Facebook Ads Library Scraper (`scraptivo/facebook-ads-scraper`) Actor

Collects public ads from Facebook Ads Library by URL, keyword, or advertiser page ID. Returns ad copy, platforms, dates, and optional advertiser details.

- **URL**: https://apify.com/scraptivo/facebook-ads-scraper.md
- **Developed by:** [Scraptivo](https://apify.com/scraptivo) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 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?

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** collects public ads from the [Facebook Ads Library](https://www.facebook.com/ads/library/) and turns them into structured records for competitive research, creative monitoring, and advertiser discovery. Provide an Ads Library URL, a keyword such as Nike, or advertiser page IDs, then export page name, ad text, CTA, platforms, dates, and destination links to JSON, CSV, Excel, or your preferred integration. Use it to archive live and inactive creatives, compare campaigns across Facebook and Instagram, and schedule recurring keyword scans. Pricing starts at **$1.70 per 1,000 ads**, with optional ad details at **$1.50 per 1,000**.

### What can you automate with Facebook Ads Library Scraper?

- **Build a searchable ad archive** — Collect live and inactive ads for any keyword, country, or advertiser page and keep creatives, copy, and landing pages in one dataset.
- **Compare creatives across platforms** — See where each ad ran on Facebook, Instagram, Messenger, Audience Network, and Threads, plus format, CTA, and destination URL.
- **Monitor competitors on a schedule** — Re-run the same query weekly or daily to spot new creatives, status changes, and impression windows without opening Ads Library by hand.
- **Enrich selected ads with advertiser context** — Turn on Include ad details to add advertiser about text, Instagram handle, page verification, spend signals, and creative variants.
- **Discover companies in a niche** — Switch to Unique advertisers only to return one row per company instead of every creative, then export the advertiser list to a sheet or CRM.
- **Feed reporting and research pipelines** — Export JSON, CSV, or Excel, or push completed runs into Google Sheets, a warehouse, or a webhook.

### Who is this scraper for?

| Team | Workflow |
|---|---|
| Media buyers and performance marketers | Track competitor creatives, CTAs, and landing pages for a keyword or brand. |
| Agencies and creative strategists | Archive ads by country, category, and platform to brief new campaigns. |
| Ad resellers and lead researchers | Use unique-advertiser mode to list companies running ads in a niche. |
| Brand and market researchers | Measure who is active, which formats they use, and how copy changes over time. |

### What data can you collect from Facebook Ads Library?

| Data group | Example fields | How it helps |
|---|---|---|
| Advertiser identity | `page_name`, `page_id`, `page_profile_url`, `page_like_count`, `page_categories` | Identify the page behind each ad and deduplicate companies with `page_id`. |
| Ad copy and CTA | `body_text`, `title`, `caption`, `link_description`, `cta_text`, `cta_type` | Compare messaging and calls to action without opening each creative. |
| Media | `display_format`, `images`, `videos`, `cards` | Review image, video, and carousel assets in the dataset. |
| Platforms and schedule | `publisher_platforms`, `is_active`, `start_date`, `end_date`, `total_active_time` | See where the ad ran and how long it has been active. |
| Reach and links | `impressions`, `targeted_countries`, `reach_estimate`, `spend`, `link_url`, `ads_library_url` | Qualify volume and open the Ads Library permalink or destination URL. |
| Ad details *(optional)* | `advertiser_about`, `ig_username`, `ig_followers`, `page_verification`, `variant_count`, `variant_ads` | Enrich a shortlist when **Include ad details** is enabled. |
| Unique advertisers *(optional)* | `record_type`, `page_id`, `ad_count`, `ads_library_url` | One company row per page when **Unique advertisers only** is enabled. |

Listing fields come from the Ads Library results. Detail fields appear only when **Include ad details** is on. Unique-advertiser rows replace per-ad records and do not include full creative copy. Some values are empty when Ads Library does not publish them.

### How to use Facebook Ads Library Scraper

1. Open the [Facebook Ads Library Scraper](https://apify.com/scraptivo/facebook-ads-scraper) on Apify.
2. Paste one or more Ads Library URLs, or enter **Search queries** such as `Nike` with a country and filters.
3. Set **Max ads / advertisers** and optional switches — Include ad details, Unique advertisers only, category, platforms, dates, or media type.
4. Run the Actor — it collects matching public Ads Library records.
5. Export the dataset or connect it to your workflow.

```json
{
    "searchQueries": ["Nike"],
    "country": "US",
    "activeStatus": "active",
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": ["RESIDENTIAL"]
    }
}
```

### Example workflow

#### Build a weekly competitor creative archive for a brand keyword

1. Schedule a Monday run with `searchQueries` = `["Nike"]`, `country` = `US`, and `activeStatus` = `active`.
2. Keep **Include ad details** off for a high-volume creative snapshot, or enable it on a smaller `maxItems` run when you need Instagram handles and variants.
3. Send new records to Google Sheets or a reporting warehouse through a webhook after each run.
4. Deduplicate user-side on `ad_archive_id` for ads, or on `page_id` when Unique advertisers only is enabled.
5. Compare `body_text`, `cta_text`, `publisher_platforms`, and `start_date` in your own sheet to spot new creatives.

The Actor returns structured Ads Library records. Filtering, scoring, and outreach happen in the tools you already use.

### Automate and integrate your results

- **Schedules** — Ads Library creatives change often. Run **daily** for active brand keywords and **weekly** for broader category scans. Create a separate schedule per query and country (for example "Nike — US" and "insurance — GB") so each task keeps its own dataset.
- **Webhooks** — Fire a webhook on run completion to push fresh ads into Google Sheets, Slack, a CRM, or a warehouse.
- **Exports and API** — Download JSON, CSV, or Excel from the Apify Console, or start a run from the API:

```shell
curl "https://api.apify.com/v2/acts/scraptivo~facebook-ads-scraper/runs?token=YOUR-APIFY-TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "searchQueries": ["Nike"],
    "country": "US",
    "activeStatus": "active",
    "maxItems": 50,
    "proxyConfiguration": {
      "useApifyProxy": true,
      "apifyProxyGroups": ["RESIDENTIAL"]
    }
  }'
```

- **Deduplication** — Each run appends a new dataset. Use `ad_archive_id` as the stable key for ads and `page_id` for unique-advertiser rows. Cap volume with `maxItems`.

### Input reference

| Field | Type | Required | Default | What it controls |
|---|---:|---|---|---|
| `startUrls` | Array of URLs | No\* | — | Facebook Ads Library search URLs. Filters encoded in the URL are used as-is. |
| `searchQueries` | Array of strings | No\* | — | Keywords to search when you are not relying only on a pasted URL. Each query is a separate search. |
| `searchType` | String | No | `keyword_unordered` | How keywords are matched: `keyword_unordered`, `keyword_exact`, or `page`. Page search is used automatically when advertiser page IDs are provided. |
| `pageIds` | Array of strings | No\* | — | Facebook page IDs for a specific advertiser (Ads Library `view_all_page_id`). |
| `country` | String | No | `US` | Ads Library country dropdown, including `ALL`. |
| `category` | String | No | `all` | `all`, `political` (issues, elections or politics), `housing`, `employment`, or `financial`. |
| `activeStatus` | String | No | `all` | `all`, `active`, or `inactive`. |
| `mediaType` | String | No | `all` | `all`, `image`, `meme` (images and memes), or `video`. |
| `publisherPlatforms` | Array of strings | No | — | `facebook`, `instagram`, `messenger`, `audience_network`, `threads`. Empty = all platforms. |
| `sortBy` | String | No | `most_recent` | `most_recent` or `impressions` (high to low). |
| `startDate` | Date | No | — | Only include ads that started running on or after this date. |
| `endDate` | Date | No | — | Only include ads that started running on or before this date. |
| `impressionWindow` | String | No | `any` | Audience window: `any`, `last_7_days`, `last_30_days`, or `last_90_days`. |
| `isTargetedCountry` | Boolean | No | `false` | Match Ads Library's targeted-country flag. |
| `includeAdDetails` | Boolean | No | `false` | Open each ad's detail pane for advertiser profile, Instagram, spend, transparency, and creative variants. Charged as `ad-details`. |
| `detailsConcurrency` | Integer | No | `8` | How many ad-detail requests run at once (1–20). Used only when Include ad details is on. |
| `uniqueAdvertisersOnly` | Boolean | No | `false` | Return one row per company instead of every ad. Charged as Unique Ads (`filter-run`) once per ad scraped, including collapsed repeats. |
| `maxItems` | Integer | No | `0` | Maximum ads (or unique advertisers) to write. `0` = unlimited. |
| `proxyConfiguration` | Proxy object | No | Apify proxy, RESIDENTIAL | Proxy settings. Residential proxies are recommended. |

\* Provide at least one Ads Library URL, search query, or advertiser page ID.

#### Which source should I use?

Paste `startUrls` when you already have an Ads Library search open and want those URL filters used as-is. Use `searchQueries` plus country and filters when you want the Actor to build the search. `pageIds` scrape a specific advertiser. You can combine sources: each URL and each query becomes its own search. Explicit filter fields overlay values parsed from a URL.

#### How does Unique advertisers only charge?

The Actor still opens every matching ad to build the company list. Unique Ads (`filter-run`) is charged **per ad scraped**, not per row written. If 100 ads collapse to 70 companies, you get **70 dataset rows** and **100 `filter-run` events**. `maxItems` caps the number of advertiser rows written, not the ads walked to produce them.

#### What does Include ad details add?

When `includeAdDetails` is true, each ad can include advertiser about text, Instagram username and followers, page verification, spend signals when present, and `variant_ads` / `variant_count`. This adds an `ad-details` charge on top of the listing charge. Unique-advertiser mode returns company rows instead of creatives, so detail enrichment applies to normal ad runs.

### Output example

Each dataset item is one ad (`record_type`: `ad`). A listing record looks like this:

```json
{
    "record_type": "ad",
    "ad_archive_id": "2895769867482327",
    "page_name": "Alli Hanson",
    "page_id": "101900028661031",
    "body_text": "Nike Ja 3 Kool-Aid men’s size 9 - $85.00",
    "title": "Nike Ja 3 Kool-Aid men’s size 9",
    "cta_text": "Contact us",
    "display_format": "IMAGE",
    "is_active": true,
    "start_date": "2026-08-31",
    "publisher_platforms": ["FACEBOOK", "INSTAGRAM"],
    "impressions": "<100",
    "link_url": "https://facebook.com/marketplace/item/1046035275085979/",
    "ads_library_url": "https://www.facebook.com/ads/library/?id=2895769867482327"
}
```

When Unique advertisers only is enabled, each row is `record_type`: `advertiser` with `page_id`, `page_name`, `ad_count`, and the advertiser Ads Library URL.

### How much does it cost to scrape Facebook Ads Library?

The Actor uses pay-per-event pricing. A one-time **Actor Start** (`apify-actor-start`) of **$0.00005** is charged at the beginning of each run. Result events:

- **Ad** (`dataset-item`) — **$1.70 / 1,000 ads** for each ad written in a normal run.
- **Ad Details** (`ad-details`) — **$1.50 / 1,000** for each ad opened when **Include ad details** is enabled.
- **Unique Ads** (`filter-run`) — **$1.70 / 1,000 ads scraped** in Unique advertisers only mode, including ads collapsed as repeats.

A listing-only run of 100 ads costs about **$0.17** plus the start fee. 1,000 ads cost **$1.70**; the same 1,000 ads with details cost **$3.20**. In unique-advertiser mode, 100 ads that collapse to 70 rows still charge **100 Unique Ads events ($0.17)**, not 70. Apify paid-plan discounts apply: ads and unique ads are **$1.60 / $1.50 / $1.40 per 1,000** on Bronze / Silver / Gold; ad details are **$1.40 / $1.30 / $1.20 per 1,000**. Residential proxy traffic is billed through your Apify proxy usage. When an event spending limit is reached, the run stops and the log reports which limit was hit.

### Reliability and responsible use

- **Proxy requirement** — The Actor defaults to the Apify proxy with the RESIDENTIAL group. Residential proxies are recommended for Ads Library.
- **Partial failures** — One failed ad or search does not stop the run; remaining searches continue.
- **Conditional fields** — Detail fields appear only when Include ad details is enabled. Unique-advertiser rows omit per-ad creative fields. Ads Library also leaves some values unset.
- **Public data** — The Actor collects publicly visible Ads Library listings and optional public detail fields.
- **Responsible use** — Use collected data in ways that comply with Meta's terms and applicable law. This Actor does not access private account data.

### Frequently asked questions

#### Can I scrape ads from Facebook Ads Library by keyword or page ID?

Yes. Enter keywords in `searchQueries` (for example `Nike`) with a `country` and filters, paste Ads Library URLs in `startUrls`, or pass `pageIds` to collect ads for a specific advertiser. At least one of those sources is required.

#### Can I schedule Facebook Ads Library Scraper to run automatically?

Yes. Open the Scheduler in Apify Console and set a daily or weekly cadence. Create separate schedules per keyword and country so each run stays focused and easier to deduplicate.

#### What counts as one result?

In a normal run, each ad written to the dataset is one Ad (`dataset-item`) event at $1.70 per 1,000. Include ad details adds one Ad Details event per enriched ad at $1.50 per 1,000. In Unique advertisers only mode, Unique Ads (`filter-run`) counts **each ad scraped** at $1.70 per 1,000, even when those ads collapse into fewer company rows.

#### Why are some fields empty?

Advertiser about, Instagram, verification, spend, and variants are collected only when Include ad details is on. Unique-advertiser rows do not include full ad copy. Ads Library also omits impressions, spend, end date, or media for some listings, so a null value usually means the library has no data for that field.

#### How do I avoid duplicate records?

The Actor appends results on every run and does not deduplicate across runs. Merge on `ad_archive_id` for ads and `page_id` for unique advertisers. Set `maxItems` to cap each run.

#### Do I need a proxy?

Residential proxies are recommended and are the default `proxyConfiguration`. If a run returns unusually few ads, confirm the RESIDENTIAL group is selected, then widen tight filters such as inactive + a rare keyword.

### Related Scraptivo automations

- [Meta Ads Scraper](https://apify.com/scraptivo/meta-ads-scraper) — collect ads from Meta’s public ad library with a complementary workflow.
- [Instagram Comment Scraper](https://apify.com/scraptivo/instagram-comment-scraper) — pull comments and commenter data from Instagram posts and reels.
- [TikTok Profile Scraper](https://apify.com/scraptivo/tiktok-profile-scraper) — collect public TikTok posts and profile metadata.
- [Twitter/X Profile Scraper](https://apify.com/scraptivo/twitter-x-profile-scraper) — extract profile and post data from X accounts.
- [Reddit Scraper](https://apify.com/scraptivo/reddit-scraper) — collect posts and discussions from Reddit communities.

### Support and custom workflows

Need a different field, source, or delivery workflow? Contact Scraptivo at scraptivo@gmail.com. Include the Actor name, sample URL, required fields, and expected volume so we can assess the request.

# Actor input Schema

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

Paste one or more Facebook Ads Library search URLs (e.g. https://www.facebook.com/ads/library/?q=Nike\&country=US). Filters encoded in the URL are used as-is. Leave empty to search with the filter fields below.

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

Keywords to search in Ads Library (e.g. Nike, insurance, crypto). Used when you are not pasting a full Ads Library URL. Each query is a separate search.

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

How keywords are matched. Page search is used automatically when advertiser page IDs are provided.

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

Optional Facebook page IDs to scrape ads for a specific advertiser (same as view\_all\_page\_id in Ads Library).

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

Country shown in the Ads Library country dropdown.

## `category` (type: `string`):

Ads Library category: all ads, issues/elections/politics, properties (housing), employment, or financial products and services.

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

Active ads, inactive ads, or both.

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

Restrict results to images, images and memes, or videos.

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

Where the ad ran. Leave empty for all platforms.

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

Most recent (Ads Library default grouping) or impressions high to low.

## `startDate` (type: `string`):

Only include ads that started running on or after this date.

## `endDate` (type: `string`):

Only include ads that started running on or before this date.

## `impressionWindow` (type: `string`):

Optional Ads Library audience window (ads seen in the last 7 / 30 / 90 days).

## `isTargetedCountry` (type: `boolean`):

Match Ads Library's is\_targeted\_country flag.

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

Open each ad's detail pane (advertiser profile, Instagram, spend, transparency, creative variants). Charged as a separate ad-details event. Requests run concurrently and each uses a rotated proxy.

## `detailsConcurrency` (type: `integer`):

How many ad-detail requests to run at once. Each request opens a new session with a rotated proxy. Only used when Include ad details is on.

## `uniqueAdvertisersOnly` (type: `boolean`):

Return one row per company instead of every ad. Charged as Unique Ads (filter-run) once per ad scraped, including ads collapsed as repeats. Example: 100 ads from 70 companies writes 70 rows and charges 100 filter-run events.

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

Maximum ads (or unique advertisers) to scrape. 0 = unlimited.

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

Apify Residential proxies are recommended for Ads Library.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=Nike&search_type=keyword_unordered"
    }
  ],
  "searchQueries": [
    "Nike"
  ],
  "searchType": "keyword_unordered",
  "country": "US",
  "category": "all",
  "activeStatus": "all",
  "mediaType": "all",
  "sortBy": "most_recent",
  "impressionWindow": "any",
  "isTargetedCountry": false,
  "includeAdDetails": false,
  "detailsConcurrency": 8,
  "uniqueAdvertisersOnly": false,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Dataset containing scraped ads or unique advertisers

## `runStats` (type: `string`):

Record counts and timestamps for this run

# 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 = {
    "startUrls": [
        {
            "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=Nike&search_type=keyword_unordered"
        }
    ],
    "searchQueries": [
        "Nike"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraptivo/facebook-ads-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 = {
    "startUrls": [{ "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=Nike&search_type=keyword_unordered" }],
    "searchQueries": ["Nike"],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scraptivo/facebook-ads-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 '{
  "startUrls": [
    {
      "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=Nike&search_type=keyword_unordered"
    }
  ],
  "searchQueries": [
    "Nike"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call scraptivo/facebook-ads-scraper --silent --output-dataset

```

## MCP server setup

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