# Meta Ad Library Scraper (`agnes.developer.queen/meta-ad-library-scraper`) Actor

Meta Ad Library Scraper returns every ad a brand runs on Facebook and Instagram: copy, picture or video, run dates and days running, and reach, targeting and payer for ads shown in the EU. No login. $5 per 1,000 ads. Monitor mode reports new, 30/60/90-day and stopped ads.

- **URL**: https://apify.com/agnes.developer.queen/meta-ad-library-scraper.md
- **Developed by:** [Agnes Maina](https://apify.com/agnes.developer.queen) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

[![Run on Apify](https://apify.com/actor-badge?actor=agnes.developer.queen/meta-ad-library-scraper)](https://apify.com/agnes.developer.queen/meta-ad-library-scraper)

## Meta Ad Library Scraper: every ad a brand runs on Facebook and Instagram, with days running

This Meta Ad Library scraper returns every ad a brand runs on Facebook and Instagram, with the copy, the picture or video, the start date, how many days the ad has been running, and for ads shown in the EU the reach by country, age and gender and who paid for it. Search by keyword or by advertiser page. No login, no cookies.

Type in `Nike` and you get Nike's active ads as rows you can filter, sort and export to JSON, CSV or Excel. It reads the same public library Meta also calls the Facebook Ads Library, so Instagram ads and Messenger ads come back alongside the Facebook ones. Sort by `daysRunning` to find the ads a brand has kept paying for. Run it once for research, or schedule monitor mode to get only the ads a competitor launched since last time, plus the ones that crossed 30, 60 or 90 days and the ones that stopped.

### What you get

Each row is one ad from the Meta Ad Library.

| Field | What it is |
|---|---|
| `adId`, `libraryUrl` | The ad's Library ID and its page in the Ad Library |
| `advertiserName`, `advertiserId`, `advertiserUrl` | The Facebook page that runs the ad |
| `startDate`, `endDate`, `daysRunning`, `isActive` | When the ad started, when it was last seen, how many days it has run, and whether it is still running |
| `platforms` | `facebook`, `instagram`, `messenger` or `audience_network` |
| `displayFormat` | `IMAGE`, `VIDEO`, `DCO` (several versions tested at once) or `DPA` (catalog ad) |
| `headline`, `body`, `linkDescription`, `ctaText` | The ad copy as text |
| `landingUrl`, `landingDomain` | Where the ad sends people |
| `imageUrls`, `videoUrls`, `thumbnailUrl` | The creative |
| `collationCount` | How many versions of this ad Meta groups together |
| `euTotalReach`, `euReachByCountry`, `euReachByAgeGender` | People reached in the EU, by country and by age and gender, where Meta publishes it |
| `targetAges`, `targetGender`, `targetLocations` | Targeting Meta publishes for EU ads |
| `payerName`, `beneficiaryName` | Who paid for the ad and who benefits, where Meta publishes it |
| `searchTerm`, `searchAdvertiser` | The search that found this ad |
| `isNew`, `milestone`, `stopped` | Monitor mode: new since your last run, crossed 30, 60 or 90 days running, or stopped since your last run |
| `charged`, `reason` | Whether the row was charged, and why |
| `scrapedAt` | When the row was collected |

Most Ad Library scrapers hand back the raw card. This one computes `daysRunning` for every ad, reads the EU reach breakdown that Meta only shows behind a second click, and in monitor mode tells you what changed since your last run.

#### What is not returned

- Ad spend or budgets. Meta publishes spend only for political and social-issue ads, and this actor does not target those.
- Impressions, clicks, conversions or bids.
- Reach, targeting and payer for ads never shown in the EU. Meta publishes them only for EU ads. Those rows still have the ad itself.
- Ads Meta has removed from the Ad Library.

### Try it in 30 seconds

1. Open the [Store page](https://apify.com/agnes.developer.queen/meta-ad-library-scraper) and click **Try for free**.
2. Enter a page name in **Advertisers**, for example `Nike`, or a keyword in **Search terms**, for example `protein powder`.
3. Click **Start**. Open the Ads table when the run finishes, or download JSON, CSV or Excel.

Every Apify account gets $5 of free platform credit each month. At $0.005 per ad that covers about 1,000 ads.

The same run as input JSON:

```json
{ "advertisers": ["Nike"], "country": "ALL", "activeStatus": "active", "maxAdsPerSearch": 50 }
```

### Example output

One record from a real Nike run, collected on 2026-10-02. The CDN links are shortened and `euReachByCountry` is cut to 6 of its 33 countries here. The run was made before pricing was set, so `charged`, `isNew` and `milestone` are left out.

```json
{
  "adId": "1382287983621487",
  "advertiserId": "15087023444",
  "advertiserName": "Nike",
  "advertiserUrl": "https://www.facebook.com/nike/",
  "collationCount": 1,
  "startDate": "2026-09-30",
  "endDate": "2026-10-02",
  "isActive": true,
  "daysRunning": 2,
  "platforms": ["facebook", "instagram"],
  "displayFormat": "DCO",
  "headline": "Festive Sale",
  "body": "Up to 40% off* is here. Get an extra 15% off from now till 5 October. Use code GEARUP",
  "linkDescription": "Nike - Official Online Store for Athletic Shoes, Clothing & Sports Gear. Shop the latest Nike products and enjoy free shipping.",
  "ctaText": "Shop now",
  "landingUrl": "https://www.nike.in/lp/eoss-mweb",
  "landingDomain": "nike.in",
  "imageUrls": [],
  "videoUrls": ["https://video-hou1-1.xx.fbcdn.net/o1/v/t2/f2/m366/AQO96AbQbm...", "https://video-hou1-1.xx.fbcdn.net/o1/v/t2/f2/m366/AQNptjGKuE..."],
  "thumbnailUrl": "https://scontent-hou1-1.xx.fbcdn.net/v/t39.35426-6/832745501...",
  "libraryUrl": "https://www.facebook.com/ads/library/?id=1382287983621487",
  "euTotalReach": 22032,
  "euReachByCountry": { "PT": 3701, "IT": 2842, "ES": 2821, "GR": 1465, "RO": 1315, "FR": 1030 },
  "euReachByAgeGender": {
    "18-24": { "male": 709, "female": 290, "unknown": 247 },
    "25-34": { "male": 2725, "female": 1160, "unknown": 412 },
    "35-44": { "male": 3163, "female": 1707, "unknown": 368 },
    "45-54": { "male": 2551, "female": 1741, "unknown": 301 },
    "55-64": { "male": 1653, "female": 1650, "unknown": 238 },
    "65+": { "male": 1281, "female": 1749, "unknown": 162 }
  },
  "targetAges": null,
  "targetGender": "All",
  "targetLocations": null,
  "payerName": null,
  "beneficiaryName": null,
  "searchTerm": null,
  "searchAdvertiser": "Nike",
  "stopped": false,
  "reason": "ad with advertiser, start date and content",
  "scrapedAt": "2026-10-02T09:56:34.247Z"
}
```

### Pricing

Pay per event. No monthly fee.

| Event | Price | When you pay |
|---|---|---|
| Actor start | $0.00005 | Once per run |
| Ad | $0.005 | An ad is delivered with its advertiser, its start date and its creative (copy, picture or video) |

Worked example: 1,000 ads cost 1,000 x $0.005 = $5, plus $0.00005 for the run start.

Rows without a start date or a creative are still delivered, with `charged: false`, and cost $0. EU reach, targeting and payer are included in the ad price. In monitor mode you pay only for ads that are new since your last run; milestone and stopped rows are free.

### How this compares

Live Apify Store data from 2026-10-02 for "facebook ad library" and "meta ad library". Prices are the published per-ad price on the free plan. "—" means the listing does not say.

| Actor | Price per ad | Days running | EU reach by country, age and gender | Monitor mode | Login needed |
|---|---|---|---|---|---|
| This actor | $0.005, all detail included | Yes | Yes | Yes, new, 30/60/90-day and stopped ads | No |
| apify/facebook-ads-scraper | $0.0058 | — | — | — | No |
| curious\_coder/facebook-ads-library-scraper | $0.00075 | — | — | — | — |
| constructive\_calm/facebook-ad-library-pro | $0.00049, plus $0.00025 for details | — | — | — | — |
| whoareyouanas/meta-ad-scraper | $0.01 | — | — | — | — |

If you only need raw cards in bulk, curious\_coder is cheaper. If you need to know how long each ad has run and who it reached, compare against the per-ad plus detail prices.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `searchTerms` | array | | Keywords, for example `protein powder`. Add at least one search term or advertiser |
| `advertisers` | array | | Facebook page names, page IDs or page URLs, for example `Nike`. Add at least one search term or advertiser |
| `country` | string | `ALL` | Two-letter country code such as US, GB or DE. Only ads shown in that country are delivered |
| `activeStatus` | string | `active` | `active`, `inactive` or `all` |
| `mediaType` | string | `all` | `all`, `image`, `video`, `meme` or `none` |
| `minDaysRunning` | integer | 0 | Deliver only ads running for at least this many days. 0 turns the filter off |
| `maxAdsPerSearch` | integer | 100 | Stop after this many ads per search term or advertiser |
| `fetchEuDetails` | boolean | true | Read reach, targeting and payer for EU-eligible ads |
| `onlyNewSinceLastRun` | boolean | false | Monitor mode. Later runs of the same search deliver only new, milestone and stopped ads |
| `proxyConfiguration` | object | Apify residential | The Ad Library blocks datacenter addresses, so residential proxy is the default |

#### Monitor mode

Set `onlyNewSinceLastRun` to true and schedule the run daily or weekly. The first run delivers current ads up to your limit and remembers every ad it saw. Each later run delivers ads that appeared since, marked `isNew` and charged, plus free rows for ads that crossed 30, 60 or 90 days running (`milestone`) and ads that disappeared from the Library (`stopped`).

### Use cases

- Competitor ad monitoring. Schedule monitor mode weekly on ten competitors and get only the new ads, the ones that have proven themselves by running 90 days, and the ones that got cut.
- Winning-ad research. Set `minDaysRunning` to 30 and search a category. Ads a brand keeps paying for are the ads that work.
- Agency pitches. Pull a prospect's rivals' active ads and open the pitch with their copy and creative.
- EU market research. Sort by `euTotalReach` and read `euReachByCountry` to see where a brand is actually spending in Europe.
- Creative swipe file. Export image and video links with headline and body for a whole category.

### Integrations

Run it and get the dataset in one request:

```bash
curl -X POST "https://api.apify.com/v2/acts/agnes.developer.queen~meta-ad-library-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"advertisers": ["Nike"], "maxAdsPerSearch": 50}'
```

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("agnes.developer.queen/meta-ad-library-scraper").call(
    run_input={"advertisers": ["Nike"], "maxAdsPerSearch": 50}
)
for ad in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(ad["daysRunning"], ad["headline"], ad["libraryUrl"])
```

Node.js:

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('agnes.developer.queen/meta-ad-library-scraper').call({
    advertisers: ['Nike'],
    maxAdsPerSearch: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, 'ads');
```

Make, n8n and Zapier: use the Apify app or node, pick "Run Actor", choose `agnes.developer.queen/meta-ad-library-scraper` and paste the input JSON. Send the dataset on to Google Sheets, Slack or your CRM. Schedules and webhooks work as with any Apify actor.

MCP server, for any MCP client:

```
https://mcp.apify.com/?tools=agnes.developer.queen/meta-ad-library-scraper
```

Ask the agent which of a competitor's ads have run longest this quarter. It should read `daysRunning`, `headline`, `body`, `euTotalReach` and `libraryUrl`.

### FAQ

#### Is the Meta Ad Library free?

Yes. Meta runs it as a free public website at facebook.com/ads/library. It has no export and its official API covers only political and social-issue ads. This actor turns the same public data into rows you can export, for $5 per 1,000 ads.

#### Can I see how much a competitor spends on Facebook ads?

No. Meta publishes spend only for political and social-issue ads. For everyone else you get the ads, their start dates, how long they have run, and for EU ads the number of people reached. An ad that has run 90 days and reached 20,000 people in the EU is a strong signal of where the budget goes.

#### What does days running mean?

The number of days between the ad's start date in the Library and the day the row was collected, or the ad's end date if it stopped. Brands keep paying for ads that work, so long-running ads are usually the winners.

#### Why do some rows have no EU reach?

Meta publishes reach, targeting and payer only for ads shown in the EU. Ads that never ran there have no such data to read, and `euTotalReach` is null. You still get the ad, its dates and its creative.

#### Does it get video ads?

Yes. Video ads return the video file links in `videoUrls` and a still in `thumbnailUrl`. Set `mediaType` to `video` to get only those.

#### Why was an ad not charged?

The Library gave no start date or no creative for it, usually a card still loading or an ad Meta has partially removed. The row is still delivered with `charged: false`, the `reason` field says why, and `libraryUrl` still opens it. You pay $0 for it.

#### Can I monitor a brand weekly?

Yes. Turn on `onlyNewSinceLastRun` and add a weekly schedule in Apify. The first run sets the baseline, and each later run delivers and charges only for new ads, with free rows for milestones and stopped ads.

#### Why did an advertiser name return nothing?

The name must match a Facebook page. The actor searches the name and takes the page whose name matches exactly, so use the name as it appears on the page, or paste the page URL or page ID instead.

#### Do I need a Facebook account or cookies?

No. The actor reads the public Ad Library without logging in.

#### Is it legal to scrape the Meta Ad Library?

The actor reads only public pages that Meta publishes for anyone to see, and it collects no personal data. You are responsible for how you use the data and for following the laws and terms that apply to you. Ask a lawyer if you are unsure about your use case.

### Support

Open an issue in the Issues tab on the [Store page](https://apify.com/agnes.developer.queen/meta-ad-library-scraper). Bug reports with a run ID get fixed fastest.

# Actor input Schema

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

Keyword searches. Add at least one search term or advertiser.

## `advertisers` (type: `array`):

Page names, page IDs or Facebook page URLs. Add at least one search term or advertiser.

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

Country where the ad was shown, or ALL.

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

Which ads to include.

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

Creative format to include.

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

Include ads running for at least this many days. Zero disables the filter.

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

Maximum ads for each search job.

## `fetchEuDetails` (type: `boolean`):

Read reach, targeting and payer information for EU-eligible ads.

## `onlyNewSinceLastRun` (type: `boolean`):

Report new ads, longevity milestones and stopped ads since the previous run.

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

Residential proxy for the public Ad Library.

## Actor input object example

```json
{
  "searchTerms": [
    "protein powder"
  ],
  "advertisers": [
    "Nike"
  ],
  "country": "US",
  "activeStatus": "active",
  "mediaType": "all",
  "minDaysRunning": 0,
  "maxAdsPerSearch": 50,
  "fetchEuDetails": true,
  "onlyNewSinceLastRun": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `ads` (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 = {
    "searchTerms": [
        "protein powder"
    ],
    "advertisers": [
        "Nike"
    ],
    "country": "US",
    "activeStatus": "active",
    "maxAdsPerSearch": 50,
    "fetchEuDetails": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("agnes.developer.queen/meta-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": ["protein powder"],
    "advertisers": ["Nike"],
    "country": "US",
    "activeStatus": "active",
    "maxAdsPerSearch": 50,
    "fetchEuDetails": True,
}

# Run the Actor and wait for it to finish
run = client.actor("agnes.developer.queen/meta-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": [
    "protein powder"
  ],
  "advertisers": [
    "Nike"
  ],
  "country": "US",
  "activeStatus": "active",
  "maxAdsPerSearch": 50,
  "fetchEuDetails": true
}' |
apify call agnes.developer.queen/meta-ad-library-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,agnes.developer.queen/meta-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/fEzIpTrM3a1OoXWKc/builds/O677ztmfXo2E7KehM/openapi.json
