# Facebook Ads Library Scraper: Meta and Instagram ads (`pikoulas/facebook-ads`) Actor

Scrape Meta's Ad Library by keyword, advertiser page or Ad Library URL: ad text, images, videos, carousel cards, links, dates, platforms, and spend, impressions and EU reach where Meta shows them. Any country, political ads included. No login, no browser.

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

## Pricing

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

## Facebook Ads Library Scraper

Scrape Meta's Ad Library, the public archive of every ad running on Facebook, Instagram,
Messenger, Threads and the Audience Network:

- **Search terms:** the ads whose text contains a keyword, or an exact phrase.
- **Advertisers:** every ad a Facebook page runs, by page name (`Nike`), page ID or page URL.
- **Ad Library URLs:** paste a search from facebook.com/ads/library with its filters, an
  advertiser's ads (`view_all_page_id=...`), or a single ad (`?id=...`).

Every ad comes with its advertiser (name, ID, page URL, likes, categories), its text, title,
link, call to action, images, videos (HD and SD MP4s), carousel and catalog cards, the dates it
started and stopped, whether it is still running, the platforms it runs on, and how many ads
share its creative. Political and issue ads also come with who paid for them, their **spend**,
**impressions** and reach. Turn on `includeAdDetails` for what the ad's details panel shows:
its **EU reach** by country, age and gender, the ages, gender and places it targets, its payer
and beneficiary, and the advertiser's Instagram account.

You can filter by country (or all countries), active or inactive, ad category (political,
housing, employment, credit), media type, platform, language and dates. It needs no login and
no browser. It costs **$0.50 per 1,000 ads**.

### What people use it for

- **Competitor research:** every ad a competitor runs, since when, and on which platforms.
- **Creative inspiration:** the ads that have run longest, with their images and videos.
- **Political ad tracking:** who pays for issue ads, how much they spend and how many people see them.
- **Lead generation:** the businesses advertising in a niche or a country, with their pages.

### How to scrape the Facebook Ads Library

1. Click **Try for free**; Apify's free plan covers a first run.
2. Enter **Search terms**, **Advertisers (Facebook pages)** or **Ad Library URLs**, the countries, and how many ads you want.
3. Click **Start**, then download the results as JSON, CSV, Excel or HTML, or read them through
   the API.

An input with more options:

```json
{
  "searchTerms": ["running shoes", "meal kit"],
  "pages": ["Nike", "https://www.facebook.com/HelloFreshUS"],
  "urls": ["https://www.facebook.com/ads/library/?active_status=all&ad_type=political_and_issue_ads&country=US&q=climate"],
  "countries": ["US", "GB"],
  "activeStatus": "active",
  "mediaType": "video",
  "platforms": ["instagram"],
  "startDate": "2026-09-01",
  "maxAds": 500
}
```

Each search term and page runs once per country; `maxAds` counts per search and country. An ad
found by two searches comes once. The filters don't apply to `urls`, which keep their own.

### Output

An ad:

```json
{
  "adArchiveId": "925321173274919",
  "url": "https://www.facebook.com/ads/library/?id=925321173274919",
  "pageId": "89516513179",
  "pageName": "Nordstrom Rack",
  "pageUrl": "https://www.facebook.com/NordstromRack/",
  "pageLikes": 2518158,
  "pageCategories": ["Clothing (Brand)"],
  "isActive": true,
  "startDate": "2026-08-03T07:00:00+00:00",
  "endDate": "2026-09-27T07:00:00+00:00",
  "platforms": ["FACEBOOK", "INSTAGRAM", "MESSENGER"],
  "displayFormat": "VIDEO",
  "title": "Fast & Free Pickup",
  "body": "Buy online and pick up in store for free! Get up to 70% off Nike, Vince, Madewell, adidas and more.",
  "caption": "Nordstromrack.com",
  "linkUrl": "https://fb.com/canvas_doc/1072291375736811",
  "ctaText": "Learn more",
  "images": [],
  "videos": [{"hdUrl": "https://video-cph2-1.xx.fbcdn.net/o1/v/t2/f2/m366/AQPMHFei….mp4", "sdUrl": "https://video-cph2-1.xx.fbcdn.net/….mp4", "previewUrl": "https://scontent-cph2-1.xx.fbcdn.net/….jpg"}],
  "cards": [],
  "collationCount": 2,
  "search": "nike",
  "country": "US"
}
```

A political ad adds its spend and reach:

```json
{
  "pageName": "Natural Allies for a Clean Energy Future",
  "title": "Accelerating Our Clean Energy Future",
  "categories": ["POLITICAL"],
  "paidFor": "Natural Allies, Inc.",
  "spend": "$10K - $15K",
  "currency": "USD",
  "impressions": ">1M",
  "reach": ">1M"
}
```

With `includeAdDetails`, an ad shown in the EU adds:

```json
{
  "euTotalReach": 1177115,
  "euAgeGenderReach": [{"country": "BE", "ageGender": [{"age": "18-24", "male": 84, "female": 57, "unknown": 2}]}],
  "targetAges": {"min": 18, "max": 65},
  "targetGender": "All",
  "targetLocations": [{"name": "Anglet, France", "type": "CITY", "excluded": false}],
  "payer": "adidas AG",
  "beneficiary": "adidas AG",
  "pageVerification": "BLUE_VERIFIED",
  "instagramUsername": "adidasoriginals",
  "instagramFollowers": 33660400
}
```

Catalog ads (`DPA`, `DCO`) show their products as `cards`, and their `title` and `body` come
from the first card.

### Use it as an API

One call runs it and returns the results as JSON (for runs under 5 minutes; longer ones start a
run and read its dataset). Apify's Python and JavaScript clients, and its Make, Zapier and n8n
integrations, work the same way.

```bash
curl -X POST "https://api.apify.com/v2/acts/pikoulas~facebook-ads/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchTerms": ["running shoes"], "countries": ["US"], "maxAds": 50}'
```

AI agents can call it as a tool through Apify's MCP server: `https://mcp.apify.com?tools=pikoulas/facebook-ads`.

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

You pay **$0.0005 per ad**, which is $0.50 per 1,000, with or without the ad details. Runs that
go through Apify's residential proxy also pay its traffic, $0.0012 per 100 KB: about 3 KB an ad,
or 15 KB with the details, so about $0.04 or $0.18 per 1,000 ads. There are no monthly fees.

### Good to know

- Meta shows spend, impressions and reach only for political and issue ads, and EU reach only
  for ads shown in the EU. Other ads have them as `null`.
- A running ad's `endDate` is today's date.
- Meta limits how fast one IP can search the library. When it starts refusing, the actor
  switches to Apify's residential proxy by itself, with its traffic charged as above.

### FAQ

#### Is it legal to scrape Meta's Ad Library?

It collects only what Meta's Ad Library shows publicly, without logging in. Scraping public data is
generally legal, but personal data is protected by laws such as the GDPR and the CCPA, and
Meta's terms may limit how you use what you collect. If you're unsure, ask a lawyer;
Apify's [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/) is a good start.

#### Something missing or not working?

Open an issue on the **Issues** tab with the input you used, or ask there for a field you need.

# Actor input Schema

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

Keywords searched in the Ad Library, as its search box does: ads whose text contains them.

## `pages` (type: `array`):

Page names (Nike), page IDs (15087023444) or page URLs (facebook.com/nike). Gives all the ads each page runs.

## `urls` (type: `array`):

Links copied from facebook.com/ads/library: a search with its filters, an advertiser's ads (view_all_page_id=...), or one ad (?id=...). The filters below don't apply to them.

## `countries` (type: `array`):

Two-letter country codes (US, GB, DE) of where the ads were shown, or ALL. Each search runs once per country.

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

How many ads to take from each search term, page or URL, in each country.

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

Ads running now, ads that stopped, or both.

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

All ads, or only political and issue ads (with their spend, impressions and who paid) or the housing, employment or credit ads Meta lists apart.

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

Only ads with images, memes (images with text), videos, or no media.

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

Only ads shown on these. Leave empty for all.

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

Only ads in these languages, as two-letter codes (en, es, de). Leave empty for all.

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

Search terms match as a whole phrase, not as separate words.

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

Only ads shown on or after this date (YYYY-MM-DD).

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

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

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

One more request per ad, for what its details panel shows: EU reach by country, age and gender, targeted ages, gender and locations, payer and beneficiary, and the advertiser's Instagram.

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

Not needed for most runs. When Meta refuses the run's IP, the actor switches to Apify's residential proxy by itself.

## Actor input object example

```json
{
  "searchTerms": [
    "running shoes"
  ],
  "countries": [
    "ALL"
  ],
  "maxAds": 20,
  "activeStatus": "active",
  "adType": "all",
  "mediaType": "all",
  "exactPhrase": false,
  "includeAdDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

## `spend` (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": [
        "running shoes"
    ],
    "maxAds": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("pikoulas/facebook-ads").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"],
    "maxAds": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("pikoulas/facebook-ads").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"
  ],
  "maxAds": 20
}' |
apify call pikoulas/facebook-ads --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pikoulas/facebook-ads"
        }
    }
}
```

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/Gkw2w8vO2CKGpBqzf/builds/5eUR2ojzxu3dngLag/openapi.json
