# Meta Ad Library Scraper with EU Reach & Creative Analysis (`maxencebernerd/meta-ad-library-scraper`) Actor

Scrape active and inactive Facebook & Instagram ads from the Meta Ad Library by keyword, page or URL, with EU reach and audience breakdown, landing pages, video transcripts, AI creative analysis and run-to-run monitoring. Pay per result.

- **URL**: https://apify.com/maxencebernerd/meta-ad-library-scraper.md
- **Developed by:** [Maxence Bernerd](https://apify.com/maxencebernerd) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 ad scrapeds

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

Meta Ad Library Scraper extracts **active and inactive Facebook & Instagram ads from the [Meta Ad Library](https://www.facebook.com/ads/library/)** by keyword, advertiser page or Ad Library URL: ad texts, titles, CTA, cleaned landing URL, image and video URLs, running time, number of variants, plus the **EU and UK transparency data** (total reach, reach by country, age and gender, targeted audience, beneficiary and payer) and the advertiser profile. Optional add-ons turn it into a creative-intelligence tool: **landing page capture**, **video transcripts with the 3-second hook**, **AI creative analysis** (hook type, angle, promise, offer, target, tone, longevity score, variant ideas) and a **monitoring mode** that reports what changed since the last run. Pay only for what you get: $0.35 per 1,000 ads, no subscription.

### What data does Meta Ad Library Scraper extract?

One dataset row per ad, flat enough for CSV and complete enough for AI agents:

| Field                                                                              | Description                                                                                                                                                                                          |
| ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `adArchiveId`, `adLibraryUrl`                                                      | Stable Meta identifier and direct link to the ad in the Ad Library                                                                                                                                   |
| `pageId`, `pageName`, `pageUrl`, `pageAdLibraryUrl`, `pageLikes`, `pageCategories` | Advertiser page and a link to all its ads                                                                                                                                                            |
| `isActive`, `startDate`, `endDate`, `daysRunning`                                  | Delivery status and dates (for active ads `endDate` is the last day seen); `daysRunning` is the public proxy for a winning ad                                                                        |
| `platforms`, `publisherPlatforms`                                                  | facebook, instagram, audience\_network, messenger, threads, whatsapp                                                                                                                                  |
| `displayFormat`                                                                    | IMAGE, VIDEO, CAROUSEL, DPA / DCO (dynamic catalog ads)                                                                                                                                              |
| `adCreativeBodies`, `adCreativeLinkTitles`, `linkDescriptions`, `linkCaptions`     | Every text variant of the creative (catalog placeholders removed)                                                                                                                                    |
| `ctaType`, `ctaText`                                                               | Call to action (`SHOP_NOW`, "Shop now")                                                                                                                                                              |
| `landingUrl`, `landingUrlRaw`, `landingDomain`, `utmParameters`                    | Destination URL with tracking parameters stripped, the original URL, and the UTM parameters as an object                                                                                             |
| `imageUrls`, `videoUrls`, `videoSdUrls`, `videoPreviewUrls`                        | Direct media URLs (full-size images, HD and SD mp4 videos, video thumbnails)                                                                                                                         |
| `collationId`, `collationCount`                                                    | Number of variants Meta groups under the same creative                                                                                                                                               |
| `euTransparency`                                                                   | `totalReach`, `reachByCountry`, `reachByAge`, `reachByGender`, targeted `locations`, `ageMin`/`ageMax`, `gender`, and the full country × age × gender `breakdown` (null when Meta publishes nothing) |
| `euBeneficiary`, `euPayer`                                                         | Who benefits from and who pays for the ad (EU disclosure)                                                                                                                                            |
| `ukTransparency`                                                                   | Same structure for ads shown in the United Kingdom                                                                                                                                                   |
| `advertiser`                                                                       | Page category, verification, likes, Instagram username and followers, about text                                                                                                                     |
| `landingPage`                                                                      | Final URL, status, title, H1, meta description, visible prices, screenshot URL (with `includeLandingPage`)                                                                                           |
| `transcript`                                                                       | Full text, language, duration, word timestamps and the spoken `hook` of the first 3 seconds (with `transcribeVideos`)                                                                                |
| `creativeAnalysis`                                                                 | AI analysis of the creative (with `enableCreativeAnalysis`), see below                                                                                                                               |
| `categories`, `disclaimers`, `spend`, `currency`, `impressions`                    | Only populated by Meta for regulated ads (political, housing, employment, financial)                                                                                                                 |
| `query`, `scrapedAt`                                                               | Which input produced the row, and when                                                                                                                                                               |

In monitoring mode, one extra row per query with `rowType: "diff-report"` describes the changes since the previous run.

No personal data is collected: everything comes from the public Ad Library, without logging in.

### How to scrape the Meta Ad Library

1. Open the Actor and enter **keywords** (`running shoes`), **advertiser pages** (a page ID, a handle such as `nike`, or a Facebook page URL) and/or **Ad Library URLs** copied from your browser with your own filters.
2. Set the **countries** (`ALL` by default), the **ad status** (active, inactive or both), the **media type**, the **platforms**, the **dates** and **Max ads per query** (default 100).
3. Keep **EU / UK transparency data** on to get reach and audience for every ad Meta discloses it for. Optionally enable **landing pages**, **video transcripts**, **AI creative analysis** and **monitoring mode**.
4. Click **Start**. Ads appear in the Output tab while the run progresses; download them as JSON, CSV, Excel or XML, or read them through the API. The **Winners** view lists the ads running for 30 days or more.

The Actor handles Meta's bot challenge, pagination, de-duplication, retries and session rotation on its own. Residential proxies (Apify Proxy) are on by default because the Ad Library challenges datacenter IPs.

### Input examples

Every active ad of three competitors, all countries, with EU reach:

```json
{
    "pageIds": ["nike", "adidas", "https://www.facebook.com/courirfr"],
    "countries": ["ALL"],
    "activeStatus": "active",
    "maxAdsPerQuery": 500,
    "includeEuTransparency": true
}
```

Video ads for a keyword in the US and the UK, transcribed and analyzed:

```json
{
    "searchQueries": ["protein powder"],
    "countries": ["US", "GB"],
    "mediaType": "video",
    "maxAdsPerQuery": 100,
    "transcribeVideos": true,
    "enableCreativeAnalysis": true
}
```

An Ad Library URL copied from the browser (its filters take precedence), with landing pages:

```json
{
    "adLibraryUrls": [
        "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=FR&q=sneakers&media_type=image"
    ],
    "includeLandingPage": true
}
```

### Output example

```json
{
    "rowType": "ad",
    "adArchiveId": "1036232222160843",
    "adLibraryUrl": "https://www.facebook.com/ads/library/?id=1036232222160843",
    "query": "page Courir (130297643710603)",
    "pageId": "130297643710603",
    "pageName": "Courir",
    "pageUrl": "https://facebook.com/courirfr",
    "pageLikes": 619289,
    "pageCategories": ["Shoes"],
    "isActive": true,
    "startDate": "2026-06-25",
    "endDate": "2026-09-29",
    "daysRunning": 96,
    "platforms": ["facebook", "instagram", "audience_network", "messenger", "threads"],
    "displayFormat": "DPA",
    "adCreativeBodies": [
        "L’été en ville avec Courir 👟, sneakers aux pieds du bleu glacé Gel-NYC au jaune Moon Shoe. Dispo sur courir.com"
    ],
    "adCreativeLinkTitles": ["Courir"],
    "linkDescriptions": ["€75", "€45", "€120"],
    "ctaType": "SHOP_NOW",
    "ctaText": "Shop now",
    "landingUrl": "https://www.courir.com/fr/c/chaussures/",
    "landingDomain": "courir.com",
    "utmParameters": null,
    "imageUrls": ["https://scontent.xx.fbcdn.net/v/t39.35426-6/730109306_....jpg"],
    "videoUrls": ["https://video.xx.fbcdn.net/o1/v/t2/f2/m366/AQNlhD782G....mp4"],
    "videoPreviewUrls": ["https://scontent.xx.fbcdn.net/v/t39.35426-6/730491380_....jpg"],
    "collationCount": 1,
    "euTransparency": {
        "totalReach": 3422646,
        "ageMin": 18,
        "ageMax": 65,
        "gender": "All",
        "locations": [
            { "name": "France", "type": "countries", "excluded": false },
            { "name": "Luxembourg", "type": "countries", "excluded": false }
        ],
        "reachByCountry": [
            { "country": "FR", "reach": 3313879 },
            { "country": "LU", "reach": 4553 }
        ],
        "reachByAge": [
            { "ageRange": "18-24", "reach": 368623 },
            { "ageRange": "25-34", "reach": 1104419 },
            { "ageRange": "35-44", "reach": 1066118 }
        ],
        "reachByGender": { "male": 1385632, "female": 1888765, "unknown": 44035 },
        "breakdown": [
            {
                "country": "FR",
                "ageGender": [{ "ageRange": "25-34", "male": 452118, "female": 640976, "unknown": 11325 }]
            }
        ]
    },
    "euBeneficiary": "Courir France",
    "euPayer": "Courir France",
    "ukTransparency": null,
    "advertiser": {
        "name": "Courir",
        "alias": "courirfr",
        "category": "Footwear store",
        "likes": 619289,
        "verification": "BLUE_VERIFIED",
        "igUsername": "courir",
        "igFollowers": 1030022,
        "igVerified": true
    },
    "scrapedAt": "2026-09-29T14:31:02.271Z"
}
```

### How much does it cost to scrape the Meta Ad Library?

Pricing is pay-per-event: you are charged only for results actually stored in your dataset. Platform usage (compute, proxies) is included.

| Event                      | Price                      | When it is charged                                                      |
| -------------------------- | -------------------------- | ----------------------------------------------------------------------- |
| Actor start                | $0.00005                   | once per run                                                            |
| `ad-scraped`               | $0.00035 ($0.35 per 1,000) | per ad row                                                              |
| `eu-transparency-enriched` | $0.0002 ($0.20 per 1,000)  | per ad for which Meta actually returned EU or UK transparency data      |
| `landing-page-captured`    | $0.003                     | per distinct landing page captured (title, H1, prices, screenshot)      |
| `video-transcribed`        | $0.01                      | per video transcribed (full transcript, word timestamps, 3-second hook) |
| `creative-analyzed`        | $0.02                      | per ad analyzed by AI                                                   |
| `monitor-diff`             | $0.05                      | per run that produced a diff report (the first, baseline run is free)   |

Examples:

| Ads    | Scraping + EU data (30 % of ads) | + creative analysis | + transcripts (40 % videos) | Weekly monitoring of 5 pages × 100 ads |
| ------ | -------------------------------- | ------------------- | --------------------------- | -------------------------------------- |
| 100    | $0.04                            | $2.04               | $2.44                       | $0.25 per week                         |
| 1,000  | $0.41                            | $20.41              | $24.41                      | —                                      |
| 10,000 | $4.10                            | $204.10             | $244.10                     | —                                      |

Ads that Meta does not disclose EU data for, failed captures, failed transcriptions and failed AI calls are never charged. Set **Maximum cost per run** in the run options to cap spending: the Actor stops cleanly when the cap is reached and says so in the log.

### AI creative analysis

Enable **Analyze creatives with AI** to add a `creativeAnalysis` object to every ad. The model (Claude Haiku) reads the ad texts, title, CTA, landing page title and the video transcript when available; the longevity score is computed from the running time, not by the model. A real example on a video ad that has been running for 169 days:

```json
{
    "adCreativeBodies": [
        "The Federal Reserve Bank of Philadelphia ran a study in 2018 on lottery winners. What they found was wild...\n\nFor every $1,000 in lottery winnings someone in a neighbourhood won... the bankruptcy rate of their NEIGHBOURS went up by 2.4%.\n\nNot the winners. The neighbours."
    ],
    "daysRunning": 169,
    "creativeAnalysis": {
        "hookType": "number",
        "hookText": "The Federal Reserve Bank of Philadelphia ran a study in 2018 on lottery winners. What they found was wild...",
        "angle": "wealth psychology, breaking the comparison trap",
        "mainPromise": "Learn how comparing yourself to others' financial wins can sabotage your own money decisions and break the cycle of financial stress.",
        "offer": "none",
        "offerText": null,
        "cta": "Visit Instagram profile",
        "likelyTarget": "people struggling with money, aspiring entrepreneurs, social comparison victims",
        "tone": "eye-opening, cautionary",
        "longevityScore": 98,
        "variantSuggestions": [
            "Open with the immediate consequence: 'Your neighbor won money and you went broke—here's the psychology behind it'",
            "Reframe as an opportunity: 'The neighbors who stayed broke had one thing in common—discover what they missed'",
            "Make it personal and urgent: 'Every time someone around you succeeds, you're statistically at greater risk—here's how to fix that'"
        ],
        "model": "claude-haiku-4-5"
    }
}
```

`hookType` is one of `question`, `number`, `before_after`, `testimonial`, `problem_solution`, `other`; `offer` is one of `discount`, `free_trial`, `free_shipping`, `bundle`, `none`. Ads are processed in batches of 10, in their original language.

### Video transcripts

Enable **Transcribe video ads** to add a `transcript` object to every video ad: the full text, the detected language, the duration, word-level timestamps and `hook`, the words spoken in the first 3 seconds. Music-only videos yield an empty transcript and are not charged. Transcripts feed the creative analysis when both options are on.

### Monitoring mode: what changed since last week?

Enable **Monitoring mode** and schedule the run. Each query keeps a snapshot in a named key-value store (`meta-ad-library-monitor`); from the second run on, the Actor adds a `diff-report` row per query and stores it as `DIFF-<queryKey>` in the run's key-value store:

```json
{
    "rowType": "diff-report",
    "query": "page Courir (130297643710603)",
    "previousRunAt": "2026-09-22T06:00:12.000Z",
    "currentRunAt": "2026-09-29T06:00:09.000Z",
    "previousAdCount": 118,
    "currentAdCount": 124,
    "newAds": [
        {
            "adArchiveId": "1036232222160843",
            "adLibraryUrl": "https://www.facebook.com/ads/library/?id=1036232222160843",
            "pageName": "Courir",
            "startDate": "2026-09-25",
            "daysRunning": 4,
            "text": "L’été en ville avec Courir 👟..."
        }
    ],
    "stoppedAds": [
        {
            "adArchiveId": "951438140810658",
            "adLibraryUrl": "https://www.facebook.com/ads/library/?id=951438140810658",
            "pageName": "Courir",
            "startDate": "2026-06-25",
            "daysRunning": 90,
            "text": "Jusqu'à -30% sur une sélection Courir."
        }
    ],
    "winners": [
        {
            "adArchiveId": "2003475120600590",
            "adLibraryUrl": "https://www.facebook.com/ads/library/?id=2003475120600590",
            "pageName": "Courir",
            "startDate": "2026-02-19",
            "daysRunning": 222,
            "text": "Exclusivité Courir : découvrez les nouvelles collections adidas Originals dès aujourd'hui ! 🔥"
        }
    ],
    "changedCreatives": [],
    "summary": "page Courir (130297643710603): 124 ads now vs 118 on 2026-09-22 — 9 new, 3 stopped, 41 running 30+ days, 0 changed creative."
}
```

`newAds` are ads not seen in the previous run, `stoppedAds` those that became inactive or disappeared (only when the result set was not capped by `maxAdsPerQuery`), `winners` the ads running for 30 days or more, `changedCreatives` the ads whose copy, CTA, landing URL or media changed. Dynamic catalog ads rotate their products on every load; their images and titles are ignored on purpose.

#### Watch 5 competitors every Monday and post the diff to Slack

1. Create a **Task** from the Actor with `pageIds` set to the 5 competitor pages, `activeStatus: "active"`, `maxAdsPerQuery: 300`, `monitoringMode: true`.
2. In the task's **Schedules** tab, add a schedule: `0 7 * * 1` (every Monday at 07:00).
3. In the task's **Integrations** tab, add the **Slack** integration (or a generic **Webhook** on the `ACTOR.RUN.SUCCEEDED` event pointing to your Make, n8n or Zapier scenario). The payload contains the run and dataset IDs; the `diff-report` rows are read with the dataset API, filtered on `rowType = diff-report`, and the `summary` field is ready to post as is.

The first run stores the baseline for free; every following Monday costs 5 × 300 × $0.00035 + $0.05 ≈ $0.58.

### How does it compare?

Facts as published on Apify Store on 29 September 2026 (prices for the free plan):

|                                                 | This Actor                         | memo23 / facebook-ads-library-scraper-ppe | jmlp / meta-ad-library-scraper                 | azzouzana / meta-facebook-instagram-ads-library | curious\_coder / facebook-ads-library-scraper |
| ----------------------------------------------- | ---------------------------------- | ----------------------------------------- | ---------------------------------------------- | ----------------------------------------------- | -------------------------------------------- |
| Price per 1,000 ads                             | $0.35                              | $0.50 + $0.05 per run                     | $0.15 + platform usage billed to you (≈ $0.25) | $0.50 (+ $0.50 with details)                    | $0.75                                        |
| Keywords, pages, URLs as input                  | yes                                | yes                                       | yes                                            | URL only                                        | URL only                                     |
| EU reach, audience, payer                       | yes, +$0.20 per 1,000 when present | yes                                       | no                                             | yes, +$0.50 per 1,000                           | yes                                          |
| UK transparency, advertiser profile             | yes                                | no                                        | no                                             | partial                                         | yes (UK)                                     |
| Cleaned landing URL + UTM, landing page capture | yes, capture $0.003                | link only                                 | link only                                      | link only                                       | link only                                    |
| Video transcript with hook                      | $0.01 per video                    | ≈ $0.05 per video                         | no                                             | no                                              | no                                           |
| AI creative analysis                            | $0.02 per ad                       | no                                        | no                                             | no                                              | no                                           |
| Diff between runs                               | $0.05 per run                      | new-ads-only filter                       | no                                             | no                                              | no                                           |
| Flat, null-filled output schema with views      | yes                                | raw Meta JSON                             | yes                                            | raw Meta JSON                                   | raw Meta JSON                                |

### Use cases

- **Competitive intelligence** — pull every active ad of your competitors, sort by `daysRunning`, read the winners' hooks and offers.
- **Creative research for UGC creators and agencies** — filter video ads by keyword, transcribe them and get the hook, angle and CTA of the top performers in one table.
- **Weekly monitoring** — schedule the monitoring mode on your clients' competitors and receive the new, stopped and long-running ads in Slack.
- **EU market sizing** — reach by country, age and gender for any advertiser active in Europe, data that the Ad Library shows but the official API restricts.
- **Data for AI agents** — clean JSON with stable IDs, ready for RAG pipelines or agents through the Apify MCP server.

### Using the Actor from code

Run it and read the results with the Apify API:

```bash
curl -X POST "https://api.apify.com/v2/acts/maxencebernerd~meta-ad-library-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries": ["gymshark"], "countries": ["ALL"], "maxAdsPerQuery": 50}'
```

JavaScript (`npm install apify-client`):

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('maxencebernerd/meta-ad-library-scraper').call({
    pageIds: ['nike', 'adidas'],
    countries: ['ALL'],
    maxAdsPerQuery: 200,
    enableCreativeAnalysis: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const winners = items.filter((ad) => ad.rowType === 'ad' && ad.daysRunning >= 30);
console.log(winners.map((ad) => [ad.pageName, ad.daysRunning, ad.creativeAnalysis?.hookType]));
```

Python (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("maxencebernerd/meta-ad-library-scraper").call(run_input={
    "searchQueries": ["protein powder"],
    "countries": ["US", "GB"],
    "mediaType": "video",
    "transcribeVideos": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["rowType"] == "ad" and row.get("transcript"):
        print(row["pageName"], row["daysRunning"], "days |", row["transcript"]["hook"])
```

#### MCP: use it from Claude, Cursor or any AI agent

The Actor is exposed through the [Apify MCP server](https://mcp.apify.com). Add it to your MCP client (example for Claude Desktop):

```json
{
    "mcpServers": {
        "apify": {
            "url": "https://mcp.apify.com?tools=maxencebernerd/meta-ad-library-scraper",
            "headers": { "Authorization": "Bearer <YOUR_APIFY_TOKEN>" }
        }
    }
}
```

Then ask your agent: *"Find the 50 longest-running Gymshark ads in the EU and summarize their hooks and offers."* The agent calls the Actor, waits for the dataset and reads the rows.

### Integrations

Every run can trigger Slack, Zapier, Make, n8n, Google Sheets, Google Drive, Airbyte, webhooks or any other [Apify integration](https://apify.com/integrations). The dataset is also readable through the [LangChain](https://python.langchain.com/docs/integrations/document_loaders/apify_dataset) and LlamaIndex Apify loaders. Schedule the Actor from the **Schedules** tab for continuous monitoring.

### FAQ

**How is this different from the official Ad Library API?**
Outside the EU and the UK, the official API only returns political and social-issue ads, requires an identity-verified Facebook account and an app, and does not give media URLs, CTA or page likes. This Actor reads the public Ad Library interface, the same pages anyone can open without logging in, and returns commercial ads from every country with their creatives, plus the EU/UK transparency data.

**Is it legal to scrape the Ad Library?**
The Ad Library is a public transparency repository that Meta must publish under the EU Digital Services Act, consultable without an account. The Actor collects only what the Library shows to a logged-out visitor, never logs in and collects no personal data of users. Ad creatives remain the property of their advertisers: the Actor returns their URLs and does not re-host media. You remain responsible for how you use the data. Read Apify's [legal guide to web scraping](https://blog.apify.com/is-web-scraping-legal/).

**Why do some ads have no EU data?**
Meta publishes EU transparency only for ads that reached the EU, and even then not for all of them (in our tests, 30 % to 55 % of a French retailer's ads carried it). UK ads carry `ukTransparency` without beneficiary and payer. Ads restricted to other countries never have it; the Actor skips the extra call and the charge for those.

**Are inactive and removed ads available?**
Inactive ads are available for one year when they reached the EU or the UK (choose `inactive` or `all`). Commercial ads shown only elsewhere disappear from the Library when they stop, and ads removed by Meta are not returned. `spend` and `impressions` exist only for regulated ads.

**How fresh is the data?**
Every run fetches live data at the time it runs; `endDate` of an active ad is the last day Meta saw it. Media URLs are signed by Meta's CDN and expire after a few days: download what you need promptly.

**What if Meta blocks the run?**
The Ad Library answers empty results to IPs that query too fast. The Actor paces its requests, rotates residential sessions, changes IP during long queries and retries each query up to three times; a query that still returns nothing is reported as empty and never charged. Failed queries are listed in the `FAILED-SOURCES` record of the key-value store.

**Can I request a feature or report a problem?**
Use the **Issues** tab of the Actor. Custom extractions and integrations are available on request.

# Actor input Schema

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

Words to search in ad texts, exactly like the search box of the Ad Library (e.g. `running shoes`, `Nike`). Each keyword is searched separately across the selected countries.

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

`keyword_unordered` finds ads containing all the words in any order; `keyword_exact_phrase` requires the exact phrase.

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

Numeric Facebook page IDs (e.g. `15087023444`), page handles (`nike`) or Instagram usernames (`@nike`). Names are resolved through the Ad Library advertiser search; ambiguous names use the first suggestion and a warning is logged.

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

Facebook page URLs (`https://www.facebook.com/nike`, `facebook.com/profile.php?id=...`) or Ad Library advertiser URLs (`...?view_all_page_id=...`). Every ad of the page matching the filters below is returned.

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

Result URLs copied from facebook.com/ads/library with your own filters (country, status, media type, dates, platforms) — they take precedence over the filters below. Single-ad URLs (`?id=...`) are also accepted.

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

ISO-2 country codes where the ads were shown (`US`, `FR`, `DE`...). `ALL` (default) searches every country. EU countries return the EU transparency data (reach, audience).

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

`active`: ads currently running; `inactive`: ads that stopped; `all`: both. Inactive commercial ads are only kept by Meta for ads that reached the EU or the UK (one year).

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

Filter ads by creative type.

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

Only ads shown on these platforms. Leave empty for all.

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

ISO 639-1 language codes of the ad text (`en`, `fr`, `de`...). Leave empty for all.

## `startDateMin` (type: `string`):

Only ads that were running on or after this date (YYYY-MM-DD).

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

Only ads that were running on or before this date (YYYY-MM-DD).

## `maxAdsPerQuery` (type: `integer`):

Upper limit of ads returned for each keyword, page or URL. Cost scales with the number of ads returned.

## `includeEuTransparency` (type: `boolean`):

Fetch the transparency details of each ad: total EU reach, reach by country, age and gender, targeted locations, age range and gender, beneficiary and payer, plus advertiser profile (likes, Instagram followers, verification). Charged only for ads that actually have EU or UK data (event `eu-transparency-enriched`).

## `includeLandingPage` (type: `boolean`):

Open the landing page of each ad: final URL after redirects, page title, H1, visible prices and a screenshot stored in the key-value store. Charged per page captured (event `landing-page-captured`).

## `transcribeVideos` (type: `boolean`):

Transcribe the audio of video ads and isolate the spoken hook of the first 3 seconds. Charged per video transcribed (event `video-transcribed`).

## `enableCreativeAnalysis` (type: `boolean`):

For each ad: hook type, marketing angle, main promise, offer, CTA, likely target, tone, longevity score and 3 variant suggestions. Charged per ad analyzed (event `creative-analyzed`).

## `monitoringMode` (type: `boolean`):

Compare this run with the previous run of the same queries: new ads, stopped ads, long-running winners (30+ days) and changed creatives. Adds a `diff-report` row and stores the report in the key-value store. Charged once per run (event `monitor-diff`).

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

Residential Apify Proxy is the default: the Ad Library challenges datacenter IPs. The search itself is not geo-restricted; the proxy country only changes the language of a few labels (page categories), US keeps them in English.

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

Number of queries processed in parallel (one browser session each).

## `debugDumpRaw` (type: `boolean`):

Support option. Saves the raw GraphQL pages into the key-value store (RAW-\* records).

## Actor input object example

```json
{
  "searchQueries": [
    "nike"
  ],
  "searchType": "keyword_unordered",
  "countries": [
    "ALL"
  ],
  "activeStatus": "active",
  "mediaType": "all",
  "maxAdsPerQuery": 100,
  "includeEuTransparency": true,
  "includeLandingPage": false,
  "transcribeVideos": false,
  "enableCreativeAnalysis": false,
  "monitoringMode": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "maxConcurrency": 3,
  "debugDumpRaw": false
}
```

# Actor output Schema

## `results` (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 = {
    "searchQueries": [
        "nike"
    ],
    "countries": [
        "ALL"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("maxencebernerd/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 = {
    "searchQueries": ["nike"],
    "countries": ["ALL"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("maxencebernerd/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 '{
  "searchQueries": [
    "nike"
  ],
  "countries": [
    "ALL"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call maxencebernerd/meta-ad-library-scraper --silent --output-dataset

```

## MCP server setup

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