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

See the ads any brand or keyword is running on Facebook and Instagram right now: ad wording, headline, button, landing link, format, placements and run dates. Move the start-date limit backwards to reach older ads. No account and no login needed.

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

## Pricing

$1.00 / 1,000 ad collecteds

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?

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 Ad Library Scraper

See what a brand is advertising right now. Give this actor a brand name, a
product, a slogan or any keyword, and it returns the ads Facebook lists publicly
for that search — the ad wording, the headline, the button, the landing link, the
format, where each ad runs and when it started. No account, no login and no
personal details are needed; it reads only what Facebook already shows to
everyone.

### What you can do with it

- **Watch a competitor's live creative.** Pull the ads a rival is running today,
  and re-run it weekly to see what changed.
- **Build a swipe file.** Collect winning ad wording, headlines and buttons
  across a whole category in one run.
- **Find the landing pages behind the ads.** Every ad brings its destination
  link, so you can see which offers and pages a brand is pushing.
- **Spot new campaigns early.** Ads that started in the last few days show up
  with their start date attached.
- **Compare formats and placements.** See at a glance who is running video, who
  is running carousels, and which of Facebook, Instagram, Messenger and Audience
  Network each ad is booked on.
- **Feed a dashboard.** Schedule it and append every run to the same dataset for
  a rolling record of a category's advertising.

### What you get

One row per ad:

```
{
  "searchTerm": "nike",
  "country": "US",
  "adArchiveId": "1869276447125570",
  "pageId": "15087023444",
  "pageName": "Nike",
  "pageUrl": "https://www.facebook.com/nike/",
  "pageCategories": ["Sportswear"],
  "pageLikes": 39578020,
  "bodyText": "Gear up for the season with the latest from Nike.",
  "title": "Nike: Shoes, Apparel, Stories",
  "ctaType": "INSTALL_MOBILE_APP",
  "ctaText": "Install now",
  "linkUrl": "http://itunes.apple.com/app/id1095459556",
  "linkDescription": null,
  "displayFormat": "DPA",
  "publisherPlatforms": ["FACEBOOK", "INSTAGRAM", "AUDIENCE_NETWORK", "MESSENGER"],
  "startDate": "2026-03-17T07:00:00.000Z",
  "endDate": "2026-08-01T07:00:00.000Z",
  "isActive": true,
  "variantCount": null,
  "mediaUrls": ["https://scontent.xx.fbcdn.net/v/t39.35426-6/..."],
  "carouselCards": [
    {
      "title": "Nike",
      "bodyText": "Celebrate your birthday with Nike.",
      "caption": null,
      "linkUrl": "https://www.nike.com/",
      "linkDescription": null,
      "ctaText": "Install now",
      "ctaType": "INSTALL_MOBILE_APP",
      "imageUrl": "https://scontent.xx.fbcdn.net/v/t39.35426-6/...",
      "videoUrl": null
    }
  ],
  "availability": "OK",
  "sourceUrl": "https://www.facebook.com/ads/library/?id=1869276447125570",
  "scrapedAt": "2026-08-01T12:00:00.000Z"
}
```

### Input reference

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `searchTerms` | list of text | `["nike"]` | Brands, products, slogans or keywords. Each one is searched separately. Required. |
| `country` | select | `US` | Browse from this country. Facebook shows a different set of ads in each country, so this changes the results as well as the point of view. `All countries` is supported. |
| `adType` | select | `all` | `All ads`, or narrow the results to `Political and issue ads` only. |
| `activeStatus` | select | `all` | Keep ads that are still running, ads that have stopped, or both. |
| `startDateMax` | text | empty | Optional calendar date, `YYYY-MM-DD`. Returns ads that started on or before it. This is how you reach an older set of ads — see the limits below. |
| `maxAdsPerTerm` | integer | `30` | How many ads to keep per search term, up to 30. |

### Output fields

| Field | Type | Description |
| --- | --- | --- |
| `searchTerm` | text | The term this ad was found under. |
| `country` | text | The country the search was run for. |
| `adArchiveId` | text | Facebook's own identifier for the ad. Unique per row. |
| `pageId` | text | Numeric identifier of the advertising Page. |
| `pageName` | text | The advertiser's name as shown on the ad. |
| `pageUrl` | text | Link to the advertiser's Page. |
| `pageCategories` | list | Categories the advertiser lists for itself. |
| `pageLikes` | number | Likes on the advertising Page. |
| `bodyText` | text | The main ad copy. |
| `title` | text | The ad headline, when there is one. |
| `ctaType` | text | The kind of action button, e.g. `SHOP_NOW`. |
| `ctaText` | text | The wording printed on the button, always reported in English so the same button reads the same way in every country. |
| `linkUrl` | text | Where the ad sends people. |
| `linkDescription` | text | The small print under the headline, when present. |
| `displayFormat` | text | `VIDEO`, `IMAGE`, `MULTI_IMAGES`, `DPA` and similar. |
| `publisherPlatforms` | list | Where the ad runs: Facebook, Instagram, Messenger, Audience Network, Threads, WhatsApp. |
| `startDate` | date | When the ad started running. |
| `endDate` | date | When it stopped, or is scheduled to stop. |
| `isActive` | boolean | Whether it was still running when collected. |
| `variantCount` | number | How many near-identical versions of this ad Facebook grouped together. |
| `mediaUrls` | list | Image and video links for the creative. |
| `carouselCards` | list | For carousel ads, each card with its own headline, text, button and link. |
| `availability` | text | `OK` for every row produced. |
| `sourceUrl` | text | The public Facebook page for this exact ad. |
| `scrapedAt` | date | When the row was collected. |

### Pricing

You pay per result. Every ad added to your dataset costs **$0.0010**, which
works out at **$1.00 per 1,000 ads**. Nothing else is charged, and a search that
finds no ads costs you nothing.

A worked example: ten search terms, each returning Facebook's full set of about
30 ads, is roughly 300 ads — about **$0.30** for the run.

### Limits & what this actor cannot do

- **A public ad search returns about 30 ads, and that set cannot be extended.**
  This is a limit Facebook places on public ad searching, not a setting. Asking
  for more than 30 per term is not possible.
- To reach beyond those 30, move the **Started on or before** date backwards.
  Each date reaches a different set of about 30. Sweeping the date backwards over
  several runs is the only way to build a deeper picture, and even then it is a
  sample rather than a complete history.
- The further back you go, the fewer ordinary ads come back. Facebook keeps
  ordinary ads publicly listed around the time they run, while political and
  issue ads stay listed for years.
- **Spending and impression figures are not published for ordinary
  advertising.** Facebook publishes those only for political and issue ads, so
  this actor does not carry them at all — the *Facebook Political Ads Scraper*
  is the one that reports them.
- **There is no breakdown of who saw an ad.** Facebook publishes no split by
  age, gender or region for any ad, so none is reported.
- **Button wording comes back in English, whichever country you search.** The
  standard Facebook buttons (`Shop now`, `Learn more`, `Sign up`) are reported in
  one language on purpose, so a French run and a US run describe the same ad the
  same way and the column can be grouped and counted. The advertiser's own copy —
  the ad text, headline and card wording — is untouched and stays in whatever
  language it was written in.
- A search term that the source turns away is tried once more before it is given
  up on, and any term that still fails is reported in the run log rather than
  passed off as a search with no ads.
- The same ad often appears under more than one search term. Each ad is produced
  once per run, and you are never charged twice for it.
- Narrowing the run status can leave you with fewer than 30 ads, because the
  filter is applied to the set Facebook returns.
- Image and video links published by Facebook are temporary and stop working
  after a while. Download anything you want to keep.
- Speed depends on the size of the job and on the source site's own response
  times, so no fixed throughput is promised.
- Facebook's terms prohibit automated access, and advertising data can include
  personal data. You are responsible for using the results lawfully, in line with
  the source site's terms and with applicable privacy law.

### FAQ

**Do I need a Facebook account?**
No. The actor reads only what Facebook publishes to everyone.

**Does it need my login or personal details?**
No. There is nothing to connect and nothing to sign in to.

**Can I schedule it?**
Yes. Schedule it daily or weekly and append every run to the same dataset to
track how a brand's creative changes over time.

**Is the data complete?**
No, and no tool can make it so. Facebook publishes about 30 ads for any one
public ad search. You can reach further back with the **Started on or before**
date, but you should treat the results as a strong sample of what an advertiser
is running, not as their entire history.

**Why is there no spending or impressions column?**
Because Facebook does not publish those figures for ordinary advertising —
they exist only for political and issue ads. Shipping permanently blank columns
would look like a collection failure, so they are left out. Use the *Facebook
Political Ads Scraper* when you need them.

**How do I get more ads for one brand?**
Use several related terms — the brand name, its product lines, its slogans — and
run the same terms again with earlier **Started on or before** dates. Each
combination reaches a different set.

**Why did a search return nothing?**
Either nobody is running ads matching that term in the chosen country, or the
term is too narrow. Try a broader keyword, or switch the country to
`All countries`.

# Actor input Schema

## `searchTerms` (type: `array`):

Brands, products, slogans or keywords to look up. Each term is searched separately and every ad found is added to the results.

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

Browse from this country. Facebook shows a different set of ads in each country, so this changes the results as well as the point of view. Choose "All countries" for a worldwide view.

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

Which ads to include. "All ads" covers everything Facebook lists publicly. "Political and issue ads" narrows the results to that category only.

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

Keep only ads that are still running, only ads that have stopped, or both. Narrowing this can leave you with fewer than the maximum.

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

Optional. A calendar date in YYYY-MM-DD form, for example 2025-01-31. Facebook returns a limited set of ads for any one search, and moving this date backwards is the way to reach an older set. Leave it empty for the most recent ads.

## `maxAdsPerTerm` (type: `integer`):

How many ads to keep for each search term. Facebook publishes about 30 ads for any one public ad search, so 30 is both the default and the ceiling.

## Actor input object example

```json
{
  "searchTerms": [
    "nike"
  ],
  "country": "US",
  "adType": "all",
  "activeStatus": "all",
  "maxAdsPerTerm": 30
}
```

# Actor output Schema

## `dataset` (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 = {
    "searchTerms": [
        "nike"
    ],
    "country": "US",
    "adType": "all",
    "activeStatus": "all",
    "maxAdsPerTerm": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("apt_marble/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 = {
    "searchTerms": ["nike"],
    "country": "US",
    "adType": "all",
    "activeStatus": "all",
    "maxAdsPerTerm": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("apt_marble/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 '{
  "searchTerms": [
    "nike"
  ],
  "country": "US",
  "adType": "all",
  "activeStatus": "all",
  "maxAdsPerTerm": 30
}' |
apify call apt_marble/facebook-ad-library-scraper --silent --output-dataset

```

## MCP server setup

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