# Facebook Ads Library Scraper — Competitor Ad Research (`inovaflow/facebook-ads-library-scraper`) Actor

Scrape the Meta Ad Library by keyword, advertiser Page or Ad Library URL. Every ad with days running, long-runner flag, active status, variations, platforms, landing page, CTA, copy and creatives. Country, status, media and date filters. No login.

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

## Pricing

from $1.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.

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

**See every ad your competitors run on Facebook and Instagram, and which ones they keep paying for.**

If you run paid social, you have opened the Meta Ad Library to peek at a competitor. It shows everything, and tells you almost nothing: no export, endless scrolling, and no column for the one number that matters, how long each ad has been running. Advertisers switch off ads that lose money. The ad a brand has been paying for since spring is the ad that works.

We built this for our own ad research first, and now we're sharing it. It reads the public Ad Library the way the website itself does (no login, no Meta token, no browser) and hands you every ad as a clean row: **days running**, a **long-runner flag**, how many **variations** use the same creative, the **platforms**, the **landing page**, the **CTA**, the **copy** and the **image and video links**. Search by keyword, by a competitor's Facebook Page, or paste any Ad Library link.

### Who it's for

- **Performance marketers**: *"Which of my competitor's ads have been live for 60+ days?"*
- **Creative strategists and agencies**: a swipe file of hooks, headlines, CTAs and videos, sorted by what lasts.
- **E-commerce and DTC brands**: *"What offers and landing pages is Gymshark pushing this month?"*
- **Founders and product marketers**: *"Who else advertises 'CRM software' in Germany, and on which platforms?"*
- **AI agents and automations**: one call, flat rows, no keys. Run it on a schedule to catch new ads.

### What you get per ad

| Field | What it tells you |
| --- | --- |
| `daysRunning`, `isLongRunner`, `startDate`, `isActive` | How long the ad has been live (to today, or to its stop date) and whether it is still running. Long-runner = 30+ days by default. |
| `variations` | How many ads share this exact creative and text: a sign the advertiser is scaling it. |
| `platforms` | Facebook, Instagram, Messenger, Threads, WhatsApp, Audience Network. |
| `landingPage`, `landingDomain`, `cta`, `displayUrl` | Where the ad sends people and what it asks them to do. |
| `title`, `body`, `linkDescription`, `cards` | The headline, the copy, and every card of a carousel or catalogue ad. |
| `thumbnailUrl`, `imageUrls`, `videoUrls`, `mediaType` | The creatives (image, video, carousel or dynamic catalogue). |
| `pageName`, `pageId`, `pageUrl`, `pageLikes`, `pageCategories` | Who is advertising. |
| `adArchiveId`, `adLibraryUrl` | The ad's own Ad Library page. |

Two table views are built in: **Ads overview** and **Creatives** (with thumbnails). The run summary (`OUTPUT`) adds a per-advertiser roll-up: ads found, active ads, long-runners, median days running, platforms, top landing domains and CTAs, and the Ad Library's own total for each advertiser.

### Options

- **Search terms**: any keyword (`running shoes`, `meal kit`). Turn on *Match the exact phrase* for word-for-word matches.
- **Advertiser Pages**: a Page URL (`facebook.com/nike`), a username (`gymshark`) or a Page ID. Usernames are looked up in the Ad Library's own advertiser search.
- **Ad Library URLs**: paste a search from facebook.com/ads/library; its own filters are kept.
- **Filters** (for search terms and Pages): country (or all countries), active / inactive / all, media type, platforms, languages, the dates the ads ran, and **Only ads running at least N days**. These are the library's own filters, so you never pay for ads you filtered out.
- **Limits**: max ads per search or advertiser, and max ads for the whole run (which also caps the cost).
- **One row per ad variation**: off by default. Ads that share a creative come back as one row with a `variations` count, the way the library shows them.

### How to set it up

1. Add a few search terms, your competitors' Facebook Pages, or Ad Library links.
2. Pick the country and whether you want active ads, inactive ads or both. Set *Only ads running at least* to 30 if you only want the proven ones.
3. Set the limits and press Start.

And that's it. The ads land in the dataset as they are found; export them to CSV, Excel or JSON, or pull them over the API.

### Pricing

**$1 per 1,000 ads** plus a $0.005 start fee. 500 ads cost about $0.51. Ads found twice, ads removed by your filters and empty runs are never charged.

> **Tip:** set *Only ads running at least* to 30 or 60 days. The filter runs inside the Ad Library, so you only pay for the long-runners you actually want to study.

### Notes

- The data is the public Meta Ad Library. Image and video links are Facebook CDN links that expire after a few days, so download the creatives you want to keep.
- Results come in the Ad Library's own relevance order. Each search's full total (`libraryTotal`) is in the run summary; the library counts past 50,000 as "50,000+".
- Residential proxy is the default and costs you nothing extra. The Ad Library rate-limits datacenter IPs after the first page (about 30 ads per search).
- Spend and impressions ranges only exist for ads about social issues, elections or politics (choose that *Ad category*).
- Use the data in line with Meta's terms and your local laws. Found a bug or need a field we don't return? Open an issue on the **Issues** tab.

# Actor input Schema

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

Keywords to search the ads for, one per line — a product, a niche, a brand (`running shoes`, `CRM software`, `nike`). Meta matches the words anywhere in the ad or the advertiser's name.

## `pageUrls` (type: `array`):

Competitors to spy on, one per line: a Facebook Page URL (`https://www.facebook.com/nike`), a Page username (`nike`) or a numeric Page ID (`15087023444`). Returns every ad that Page runs.

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

Search result links copied from facebook.com/ads/library, one per line. The filters in the link are used as they are (the filters below apply to search terms and Pages only).

## `exactPhrase` (type: `boolean`):

On = only ads containing the search term word for word (`"running shoes"`). Off = ads matching the words in any order.

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

Where the ads were shown. All countries = the advertiser's ads worldwide.

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

Active = running right now (what a competitor is spending on today). Inactive = stopped ads. All = both.

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

Only ads with this kind of creative.

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

Only ads shown on these Meta platforms. Empty = all.

## `minDaysRunning` (type: `integer`):

Keep only ads that have run for at least this many days — the long-runners an advertiser keeps paying for because they work. 0 = every ad.

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

Only ads shown on or after this day (YYYY-MM-DD). The Ad Library's own date filter: it keeps ads that had impressions in the window.

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

Only ads shown on or before this day (YYYY-MM-DD).

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

Only ads in these languages, as two-letter codes (`en`, `es`, `de`). Empty = any language.

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

All ads, or only ads about social issues, elections or politics (these also carry spend and impression ranges).

## `maxAdsPerSource` (type: `integer`):

Cap for each search term, advertiser and link. The Ad Library shows ads in its own relevance order.

## `maxAds` (type: `integer`):

Cap for the whole run — also caps what you pay.

## `longRunnerDays` (type: `integer`):

An ad running at least this long gets `isLongRunner: true`. Advertisers stop ads that lose money, so a long-running ad is usually a profitable one.

## `expandVariations` (type: `boolean`):

The Ad Library groups ads that use the same creative and text ("3 ads use this creative"). Off = one row per creative with a `variations` count. On = also a row for every grouped ad the library lists.

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

How many searches run at once, each in its own browser-like session.

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

Residential proxy by default: the Ad Library rate-limits datacenter IPs after the first page. Traffic is small (about 4 KB per ad).

## Actor input object example

```json
{
  "searchTerms": [
    "running shoes",
    "meal kit delivery"
  ],
  "pageUrls": [
    "https://www.facebook.com/nike",
    "gymshark",
    "15087023444"
  ],
  "adLibraryUrls": [
    "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&q=protein%20powder&search_type=keyword_unordered&media_type=all"
  ],
  "exactPhrase": false,
  "country": "ALL",
  "activeStatus": "active",
  "mediaType": "all",
  "platforms": [],
  "minDaysRunning": 0,
  "languages": [],
  "adType": "all",
  "maxAdsPerSource": 20,
  "maxAds": 40,
  "longRunnerDays": 30,
  "expandVariations": false,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

One row per ad creative: advertiser, days running, long-runner flag, active flag, variations, platforms, copy, CTA and landing page.

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

The swipe-file view: thumbnail, copy, CTA, landing page and the full image and video URLs.

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

Ads delivered, long-runners, what could not be found, the per-source report and a per-advertiser roll-up (ads, active, long-runners, median days running, platforms, top landing domains and CTAs).

# 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": [
        "running shoes"
    ],
    "pageUrls": [
        "https://www.facebook.com/nike"
    ],
    "maxAdsPerSource": 20,
    "maxAds": 40,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("inovaflow/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 = {
    "searchTerms": ["running shoes"],
    "pageUrls": ["https://www.facebook.com/nike"],
    "maxAdsPerSource": 20,
    "maxAds": 40,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("inovaflow/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 '{
  "searchTerms": [
    "running shoes"
  ],
  "pageUrls": [
    "https://www.facebook.com/nike"
  ],
  "maxAdsPerSource": 20,
  "maxAds": 40,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call inovaflow/facebook-ads-library-scraper --silent --output-dataset

```

## MCP server setup

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