# Meta Ad Library Scraper — Facebook & Instagram Ads API No Login (`affiliatescope/meta-ads-scraper`) Actor

Bulk Meta Ad Library scraper — every Facebook & Instagram ad, creative, landing URL. $0.0015/ad. No login, no Graph API approval. Raw JSON passthrough. Perfect for creative and competitor research.

- **URL**: https://apify.com/affiliatescope/meta-ads-scraper.md
- **Developed by:** [AffiliateScope](https://apify.com/affiliatescope) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 8 total users, 5 monthly users, 84.4% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Meta Ad Library Scraper

**Turn Meta's Ad Library into clean, structured JSON — every ad, every creative, every landing URL from Facebook, Instagram, Messenger, and Audience Network.**

Paste any Ad Library URL, or search by keyword or Facebook Page ID. No login. No Meta developer account. No setup. Pay $0.05 per run + $0.0015 per ad.

Built on pure HTTP against Meta's internal GraphQL — no browser to crash, no DOM-scraping to maintain. Designed for scheduled scraping, agency workflows, and competitive ad intelligence at scale.

---

### Quick start

**From the Apify Console:**

1. Click **Try for free** at the top
2. In the input form, pick one:
   - Paste Ad Library URLs (Option A), or
   - Type search queries + countries (Option B)
3. Click **Start**. Watch results stream into the dataset.

**From the API (curl):**

```bash
curl -X POST 'https://api.apify.com/v2/acts/affiliatescope~meta-ads-scraper/runs?token=YOUR_APIFY_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "searchQueries": ["nike"],
    "countries": ["US"],
    "maxAdsPerSource": 500
  }'
````

Results land in the run's default dataset within seconds of the first page. Stream them via the `/dataset/items` endpoint or export as CSV, JSON, JSONL, or XLSX from the UI.

***

### What you get per ad

- **`ad_archive_id`** + direct Library URL (inside `__metadata.adLibraryUrl` — derived from the ad ID)
- **Advertiser**: Page name, ID, profile picture URL, categories, like count, profile URI
- **Full creative text**: body, title, caption, link description, byline
- **Images**: original + resized URLs, all creative variants (single, carousel, multi-card)
- **Videos**: HD + SD URLs, preview image
- **CTA**: button text + semantic type (`Shop Now`, `Learn More`, `Download`…)
- **Landing URL** with tracking parameters preserved — affiliate tags, UTMs, campaign IDs intact
- **Delivery window**: start/end dates, currently-active flag
- **Publisher mix**: Facebook, Instagram, Messenger, Audience Network
- **Reach + spend**: reach estimates, currency, spend bands (where Meta exposes them)
- **Political/issue ads**: impressions, demographic breakdown, disclaimer label
- **`__metadata`**: run context (query, country, page number, scrape timestamp, ordering index)

Full raw Meta response passes through untouched — when Meta adds new fields, you get them automatically without waiting for a scraper update.

***

### Sample output (1 real record, trimmed)

Every record mirrors Meta's raw response shape — we don't normalize, rename, or drop fields. A `__metadata` sidecar at the top level carries the scrape context.

```json
{
  "ad_archive_id": "638485615120135",
  "ad_id": null,
  "page_id": "15087023444",
  "page_name": "Nike",
  "is_active": false,
  "start_date": 1699430400,
  "end_date": 1745650800,
  "publisher_platform": ["FACEBOOK", "INSTAGRAM", "AUDIENCE_NETWORK", "MESSENGER"],
  "currency": "",
  "spend": null,
  "impressions_with_index": { "impressions_text": null, "impressions_index": -1 },
  "reach_estimate": null,
  "categories": ["UNKNOWN"],
  "contains_digital_created_media": false,
  "contains_sensitive_content": false,
  "targeted_or_reached_countries": [],
  "snapshot": {
    "body": {
      "text": "Encuentra tu mejor estilo. Llegó el momento de que tu siguiente favorito sea el tuyo..."
    },
    "cta_text": "Install now",
    "cta_type": "INSTALL_MOBILE_APP",
    "link_url": "http://play.google.com/store/apps/details?id=com.nike.omega&...",
    "caption": "play.google.com",
    "title": "{{product.name}}",
    "link_description": null,
    "page_categories": ["Sportswear", "Product/service"],
    "page_profile_picture_url": "https://scontent.xx.fbcdn.net/v/t39.35426-6/...",
    "page_profile_uri": "https://www.facebook.com/nike",
    "page_like_count": 39643468,
    "cards": [
      { "body": "Encuentra tu mejor estilo...", "original_image_url": "https://scontent.xx.fbcdn.net/..." }
    ],
    "videos": [],
    "images": [],
    "display_format": "DCO"
  },
  "__metadata": {
    "order": 1,
    "sourceOrder": 1,
    "page": 1,
    "sourceKey": "kw:US:nike",
    "sourceType": "keyword",
    "query": "nike",
    "country": "US",
    "adLibraryUrl": "https://www.facebook.com/ads/library/?id=638485615120135",
    "scrapedAt": "2026-04-19T13:28:01.053Z"
  }
}
```

**Notes on field population:**

- **`spend`, `currency`, `reach_estimate`, `impressions_with_index.impressions_text`** only populate for **political and social-issue ads** (where Meta's DSA disclosure rules require it). Most commercial ads have empty/null values in these fields — this is Meta's choice, not a scraper limitation.
- **`cards[]`** contains one entry per creative variant (single image ads have 1 card; carousels have multiple). Each card has its own body text, image URLs, and optional video URLs.
- **`snapshot.videos` / `snapshot.images`** are set for single-creative ads; multi-creative ads carry media inside `snapshot.cards[].*_image_url` / `*_video_url` instead.
- Raw passthrough means you also receive fields not shown above: `ad_id`, `collation_count`, `collation_id`, `gated_type`, `state_media_run_label`, `regional_regulation_data`, and more — everything Meta sends, you get.

***

### Inputs

Provide **one** of these four source types, plus optional filters.

| Source              | What it does                                                                        |
| ------------------- | ----------------------------------------------------------------------------------- |
| **Ad Library URLs** | Paste any URL from `facebook.com/ads/library` — filters baked into the URL are used |
| **Search queries**  | Free-text keyword search, one per line, scoped by country                           |
| **Page IDs**        | Numeric Facebook Page IDs — returns every ad from those Pages                       |
| **Ad IDs**          | Specific `ad_archive_id` values for single-ad lookups *(v2.1)*                      |

**Filters** (apply to Query Builder sources, not pasted URLs):

- **Countries**: ISO-3166 alpha-2 (`US`, `GB`, `DE`…) or `['ALL']` for worldwide
- **Active status**: currently-running / stopped / both
- **Ad category**: all / political & social-issue / housing / employment / credit
- **Media type**: image / video / carousel / meme / text-only
- **Publisher platforms**: any subset of FB / IG / Messenger / Audience Network
- **Content languages**: ISO-639 codes
- **Date range**: `from` and `to` in `YYYY-MM-DD`
- **Sort**: total impressions (default) / most recent first

See the **Input** tab for the full schema — every field is documented with an example.

***

### Pricing

Pay only for what you scrape. No monthly minimums, no subscriptions, no commitments.

| Event           | Price   |
| --------------- | ------- |
| Actor run start | $0.05   |
| Each ad scraped | $0.0015 |

**Worked examples:**

| Use case                           | Run size    | Cost       |
| ---------------------------------- | ----------- | ---------- |
| Testing the output before deciding | 50 ads      | **$0.13**  |
| Weekly creative review for 1 brand | 500 ads     | **$0.80**  |
| Competitive intel across 5 brands  | 5,000 ads   | **$7.55**  |
| Agency monthly refresh, 30 brands  | 30,000 ads  | **$45.05** |
| Trend dataset across 50 countries  | 100,000 ads | **$150.05** |

Set a `maxTotalChargeUsd` limit in the run config and the scraper will honor it — automatic budget cap, no surprise bills.

***

### Why this scraper

| Alternative                         | Why this scraper wins                                                                               |
| ----------------------------------- | --------------------------------------------------------------------------------------------------- |
| **Meta's Graph API (ads\_archive)**  | No Business Manager approval needed. All ad types accessible, including commercial ads. Full creative fields (Graph API restricts most of them to political/issue ads). |
| **Playwright-based scrapers**       | 3× cheaper per ad. No DOM dependency — doesn't break when Meta changes their frontend.              |
| **DIY from scratch**                | Zero setup, zero maintenance. Auto-rotates when Meta changes their internal query IDs.              |
| **Manual Ad Library browsing**      | Structured JSON at scale, scheduled refresh, one-click CSV / JSON / XLSX export.                    |

***

### How it works

- **Pure HTTP against Meta's GraphQL** — no browser, no Chromium, no Puppeteer/Playwright. Significantly lower compute cost per ad than browser-based scrapers.
- **Sticky residential sessions** — one session bootstraps once, then paginates through thousands of ads on the same sticky IP. Drastically reduces the per-run handshake overhead that trips up naive scrapers.
- **Full Meta response passthrough** — output is raw JSON from Meta with a `__metadata` sidecar (query, country, page, order, timestamp). You get every field Meta exposes, not a lossy normalized subset.

***

### Reliability

Built for sustained scheduled workloads. Typical throughput on Apify residential proxy is **~100 ads per minute per source**, so a 1,000-ad single-keyword run finishes in about 10 minutes. Multi-source runs (several keywords or Page IDs together) parallelize — 10 concurrent sources triple to quadruple the effective rate. Recent production runs have completed 290+ pages with zero failed requests.

***

### Performance tuning

Two knobs shape how fast your run completes and how much memory it needs.

#### Memory (`memoryMbytes`)

Default is **512 MB** — enough for up to ~10 concurrent sources. Bump it in the Apify Console's **Memory** dropdown when you need more:

| Workload                                        | Recommended memory |
| ----------------------------------------------- | ------------------ |
| 1–10 sources (URLs, keywords, or Page IDs)      | 512 MB (default)   |
| 10–40 sources concurrent                        | 1 GB               |
| 40+ sources concurrent                          | 2 GB               |
| Single massive scrape with `maxAdsPerSource: 100,000+` | 1 GB               |

Memory is fixed at run start — Apify doesn't auto-scale mid-run. Allocating *more* than you need doesn't make the run faster; it just increases compute cost (you're billed per `memoryGB × runtime`). Allocating *less* than you need causes OOM and an aborted run. The defaults are sized for the typical scheduled-scrape workflow.

#### Concurrency (`maxConcurrency`)

Default is **3**. This controls how many *sources* (URLs, keywords, Page IDs) run in parallel. **Important mental model:**

- **Between sources**: fully parallel. 10 keywords with `maxConcurrency: 10` all scrape simultaneously.
- **Within one source**: strictly serial. Meta's pagination cursor for page 2 comes from page 1's response, so one source pages one at a time regardless of concurrency.

The scraper automatically caps effective concurrency at the number of sources you provide. If you set `maxConcurrency: 20` but pass only 1 search query, effective concurrency = 1 — the other 19 slots would sit idle and churn session bootstraps. The config panel at run start prints the effective value (e.g. `concurrency  1 (capped from 20: only 1 source)`).

**Practical guide:**

| You have                            | Set `maxConcurrency` to |
| ----------------------------------- | ----------------------- |
| 1 URL / 1 keyword / 1 Page ID       | 1                       |
| 2–5 sources                         | = number of sources     |
| 5–20 sources                        | 5 (balance throughput vs proxy-pool usage) |
| 20+ sources, time-sensitive         | 10 (then bump memory to 1 GB) |

A 10,000-ad single-keyword run at `concurrency: 1` finishes in ~100 minutes. Split into 10 keywords × 1,000 ads each with `concurrency: 10` and the same 10,000 ads finish in ~10 minutes — roughly 10× faster because all 10 sources scrape simultaneously.

***

### Integration

- **Schedule runs** from the Apify Console (hourly, daily, weekly, cron)
- **Webhooks** on run completion — Zapier, Make, n8n, Slack, or your own backend
- **Dataset API** — pull results as CSV, JSON, JSONL, or XLSX, or stream via HTTP
- **Automatic charge cap** — set `maxTotalChargeUsd` per run, scraper stops cleanly when budget is reached
- **Data-pipeline ready** — push datasets to BigQuery / Snowflake / S3 via Apify's one-click integrations

***

### FAQ

**Is this legal?**
Yes. The Meta Ad Library is a public transparency tool operated by Meta — the same data a human can browse at `facebook.com/ads/library`. We scrape only data Meta has explicitly published to this tool. No login, no personal data, no private targeting details. Residential proxies obey Meta's IP-level rate limits; sessions retire and rotate cleanly when Meta signals throttling.

**How fresh is the data?**
Real-time. Each run fetches directly from Meta's live endpoint — no caching, no intermediate storage. An ad published 5 seconds before your run will appear in the results if Meta's Ad Library has indexed it.

**Will it break when Meta changes their Ad Library?**
Unlikely. We don't scrape the DOM — we use Meta's own internal GraphQL API, which is the same pipeline Meta's own Ad Library frontend uses. When Meta deploys a backend change, the scraper auto-detects the rotation and continues working on the next request. If a change does require a manual update, we prioritize and ship it as quickly as possible.

**What about rate limits?**
Handled transparently. The scraper uses Apify's residential proxy pool (default setting) — each Crawlee session gets a sticky residential IP. On rate-limit errors, the session retires and a fresh IP picks up where the last one left off. You won't see failed requests in normal operation.

**Compared to Meta's Graph API?**
Meta's Graph API `ads_archive` endpoint gates most fields behind political/issue-ads approval, which requires Business Manager verification and takes weeks to obtain. This scraper returns every ad type Meta publishes to the Library, including commercial ads with full creative text and images — no approval required.

**GDPR / privacy compliance?**
The Ad Library publishes no PII. All personal targeting details are aggregated before Meta exposes them. The only identifiers in the output are Page IDs (corporate advertiser entities) and ad archive IDs. Spend/impression data is bucket-aggregated, not per-user.

**What if I need data you don't currently extract?**
Because we pass through Meta's raw response, every field Meta returns is in the dataset — even fields we don't explicitly document. Use `dataset.items[0]` to inspect the full shape. If a field is missing because Meta didn't include it for that ad, it's genuinely not available.

**Can I run this continuously?**
Yes. Set up a scheduled run in the Apify Console (daily, hourly, cron) and results stream into a rotating dataset. Combined with a `maxTotalChargeUsd` budget cap, you get subscription-like monthly spend predictability with per-ad billing.

**How do I export the data?**
The Apify Console offers one-click export as CSV, JSON, JSONL, or XLSX. Programmatically, fetch `/v2/datasets/{id}/items` to stream records. For data-warehouse integrations, use Apify's built-in push integrations to BigQuery, Snowflake, or S3.

***

### Support

Contact the actor owner (`affiliatescope`) via the Apify Console. We respond within one business day on weekdays. Confirmed scraper failures are triaged the same day.

***

### Keywords

Facebook Ads scraper, Meta Ad Library API, Instagram Ads scraper, ad intelligence, competitor ad research, political ad transparency, EU DSA ads dataset, ad spy tool, creative research, Facebook advertising API alternative, ad library export, competitor creative monitoring, affiliate marketing intelligence.

# Actor input Schema

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

Paste one URL per line. Filter parameters are read from each URL's query string, so whatever you see in the Ad Library UI is what you get. Supports search-result URLs, single-Page views (?view\_all\_page\_id=...), and single-ad pages (?id=...).

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

Free-text search terms, one per line. Example: `nike`, `black friday`, `home insurance quote`. Each query runs against every country in the Countries filter below.

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

Numeric Page IDs, one per line. Returns every currently-indexed ad from each Page. Find the ID in any Page's Ad Library URL: `facebook.com/ads/library/?view_all_page_id=<THIS_NUMBER>`.

## `adIds` (type: `array`):

Numeric ad\_archive\_id values, one per line. Useful for re-fetching a specific ad (e.g. `1191898553123641`). Lightweight — one ad in, one ad out.

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

ISO-3166 alpha-2 country codes, e.g. `US`, `GB`, `DE`. Defaults to `['US']`. Use `['ALL']` to scrape ads globally (no country filter).

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

`Active only` = ads currently running. `Inactive only` = ads that stopped running. `All` = both.

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

Filter by Meta's ad category. `Political & social-issue` is the only category that exposes spend, impressions, and byline fields. `Credit` maps to Meta's `Financial products and services`.

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

Filter by ad creative type. `Meme` = image with overlay text. `No media` = text-only ads.

## `publisherPlatforms` (type: `array`):

Leave empty for all platforms. Otherwise any subset of `FACEBOOK`, `INSTAGRAM`, `MESSENGER`, `AUDIENCE_NETWORK`.

## `contentLanguages` (type: `array`):

ISO-639 language codes, one per line (e.g. `en`, `de`, `es`). Empty = any language.

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

Earliest ad delivery date, `YYYY-MM-DD`. Leave empty for no lower bound.

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

Latest ad delivery date, `YYYY-MM-DD`. Leave empty for no upper bound.

## `sortBy` (type: `string`):

Order of returned ads. `Total impressions` surfaces highest-reach ads first and matches the Ad Library UI's default.

## `isTargetedCountry` (type: `boolean`):

If on, filter out ads that merely reached the country without specifically targeting it. Off = include broadly-targeted ads that happened to appear in the country.

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

Per-URL / per-query / per-Page / per-Ad-ID cap. `0` = no limit, scrape every indexed ad. A single query can return 10,000+ ads in popular verticals — set this to protect your budget and dataset size.

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

Hard cap across ALL sources combined. `0` = no global cap (only per-source caps apply).

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

Number of sources processed in parallel. **Only helps with multiple sources** — within one source, pagination is serial (each page needs the previous page's cursor), so concurrency above 1 gets automatically capped at your source count. Example: with 1 URL, effective concurrency = 1 regardless of this setting. With 10 keywords, set 5–10 to parallelize. Bumping above 10 also needs memory raised to 1 GB via the Console's Memory dropdown.

## `proxy` (type: `object`):

Residential proxy is strongly recommended — Meta aggressively rate-limits datacenter IPs. Apify RESIDENTIAL returns the highest success rate. Leave at the default unless you have a specific reason to change it.

## `runTag` (type: `string`):

Custom label copied to every record's `__metadata.runTag`. Useful when you run the scraper on a schedule and want to group or filter dataset rows by run.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=nike&search_type=keyword_unordered&sort_data[direction]=desc&sort_data[mode]=total_impressions"
    }
  ],
  "searchQueries": [],
  "pageIds": [],
  "adIds": [],
  "countries": [
    "US"
  ],
  "activeStatus": "ALL",
  "adType": "ALL",
  "mediaType": "ALL",
  "publisherPlatforms": [],
  "contentLanguages": [],
  "sortBy": "TOTAL_IMPRESSIONS_DESC",
  "isTargetedCountry": false,
  "maxAdsPerSource": 30,
  "maxAds": 0,
  "maxConcurrency": 3,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "urls": [
        {
            "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=nike&search_type=keyword_unordered&sort_data[direction]=desc&sort_data[mode]=total_impressions"
        }
    ],
    "searchQueries": [],
    "pageIds": [],
    "adIds": [],
    "countries": [
        "US"
    ],
    "publisherPlatforms": [],
    "contentLanguages": [],
    "maxAdsPerSource": 30,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("affiliatescope/meta-ads-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 = {
    "urls": [{ "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=nike&search_type=keyword_unordered&sort_data[direction]=desc&sort_data[mode]=total_impressions" }],
    "searchQueries": [],
    "pageIds": [],
    "adIds": [],
    "countries": ["US"],
    "publisherPlatforms": [],
    "contentLanguages": [],
    "maxAdsPerSource": 30,
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("affiliatescope/meta-ads-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    {
      "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&is_targeted_country=false&media_type=all&q=nike&search_type=keyword_unordered&sort_data[direction]=desc&sort_data[mode]=total_impressions"
    }
  ],
  "searchQueries": [],
  "pageIds": [],
  "adIds": [],
  "countries": [
    "US"
  ],
  "publisherPlatforms": [],
  "contentLanguages": [],
  "maxAdsPerSource": 30,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call affiliatescope/meta-ads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=affiliatescope/meta-ads-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Meta Ad Library Scraper — Facebook & Instagram Ads API No Login",
        "description": "Bulk Meta Ad Library scraper — every Facebook & Instagram ad, creative, landing URL. $0.0015/ad. No login, no Graph API approval. Raw JSON passthrough. Perfect for creative and competitor research.",
        "version": "2.0",
        "x-build-id": "O8RrPF8CZn5u6RNhs"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/affiliatescope~meta-ads-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-affiliatescope-meta-ads-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/affiliatescope~meta-ads-scraper/runs": {
            "post": {
                "operationId": "runs-sync-affiliatescope-meta-ads-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/affiliatescope~meta-ads-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-affiliatescope-meta-ads-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "urls": {
                        "title": "Ad Library URLs",
                        "type": "array",
                        "description": "Paste one URL per line. Filter parameters are read from each URL's query string, so whatever you see in the Ad Library UI is what you get. Supports search-result URLs, single-Page views (?view_all_page_id=...), and single-ad pages (?id=...).",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "searchQueries": {
                        "title": "Search queries (keywords)",
                        "type": "array",
                        "description": "Free-text search terms, one per line. Example: `nike`, `black friday`, `home insurance quote`. Each query runs against every country in the Countries filter below.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "pageIds": {
                        "title": "Facebook Page IDs",
                        "type": "array",
                        "description": "Numeric Page IDs, one per line. Returns every currently-indexed ad from each Page. Find the ID in any Page's Ad Library URL: `facebook.com/ads/library/?view_all_page_id=<THIS_NUMBER>`.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "adIds": {
                        "title": "Specific Ad archive IDs",
                        "type": "array",
                        "description": "Numeric ad_archive_id values, one per line. Useful for re-fetching a specific ad (e.g. `1191898553123641`). Lightweight — one ad in, one ad out.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "countries": {
                        "title": "Countries",
                        "type": "array",
                        "description": "ISO-3166 alpha-2 country codes, e.g. `US`, `GB`, `DE`. Defaults to `['US']`. Use `['ALL']` to scrape ads globally (no country filter).",
                        "default": [
                            "US"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "activeStatus": {
                        "title": "Active status",
                        "enum": [
                            "ALL",
                            "ACTIVE",
                            "INACTIVE"
                        ],
                        "type": "string",
                        "description": "`Active only` = ads currently running. `Inactive only` = ads that stopped running. `All` = both.",
                        "default": "ALL"
                    },
                    "adType": {
                        "title": "Ad category",
                        "enum": [
                            "ALL",
                            "POLITICAL_AND_ISSUE_ADS",
                            "HOUSING_ADS",
                            "EMPLOYMENT_ADS",
                            "CREDIT_ADS"
                        ],
                        "type": "string",
                        "description": "Filter by Meta's ad category. `Political & social-issue` is the only category that exposes spend, impressions, and byline fields. `Credit` maps to Meta's `Financial products and services`.",
                        "default": "ALL"
                    },
                    "mediaType": {
                        "title": "Media type",
                        "enum": [
                            "ALL",
                            "IMAGE",
                            "MEME",
                            "VIDEO",
                            "NONE"
                        ],
                        "type": "string",
                        "description": "Filter by ad creative type. `Meme` = image with overlay text. `No media` = text-only ads.",
                        "default": "ALL"
                    },
                    "publisherPlatforms": {
                        "title": "Publisher platforms",
                        "type": "array",
                        "description": "Leave empty for all platforms. Otherwise any subset of `FACEBOOK`, `INSTAGRAM`, `MESSENGER`, `AUDIENCE_NETWORK`.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "contentLanguages": {
                        "title": "Content languages",
                        "type": "array",
                        "description": "ISO-639 language codes, one per line (e.g. `en`, `de`, `es`). Empty = any language.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "startDate": {
                        "title": "From date",
                        "type": "string",
                        "description": "Earliest ad delivery date, `YYYY-MM-DD`. Leave empty for no lower bound."
                    },
                    "endDate": {
                        "title": "To date",
                        "type": "string",
                        "description": "Latest ad delivery date, `YYYY-MM-DD`. Leave empty for no upper bound."
                    },
                    "sortBy": {
                        "title": "Sort results",
                        "enum": [
                            "TOTAL_IMPRESSIONS_DESC",
                            "MOST_RECENT"
                        ],
                        "type": "string",
                        "description": "Order of returned ads. `Total impressions` surfaces highest-reach ads first and matches the Ad Library UI's default.",
                        "default": "TOTAL_IMPRESSIONS_DESC"
                    },
                    "isTargetedCountry": {
                        "title": "Only ads targeting the selected country",
                        "type": "boolean",
                        "description": "If on, filter out ads that merely reached the country without specifically targeting it. Off = include broadly-targeted ads that happened to appear in the country.",
                        "default": false
                    },
                    "maxAdsPerSource": {
                        "title": "Max ads per source",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Per-URL / per-query / per-Page / per-Ad-ID cap. `0` = no limit, scrape every indexed ad. A single query can return 10,000+ ads in popular verticals — set this to protect your budget and dataset size.",
                        "default": 0
                    },
                    "maxAds": {
                        "title": "Max ads total (hard cap)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Hard cap across ALL sources combined. `0` = no global cap (only per-source caps apply).",
                        "default": 0
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Number of sources processed in parallel. **Only helps with multiple sources** — within one source, pagination is serial (each page needs the previous page's cursor), so concurrency above 1 gets automatically capped at your source count. Example: with 1 URL, effective concurrency = 1 regardless of this setting. With 10 keywords, set 5–10 to parallelize. Bumping above 10 also needs memory raised to 1 GB via the Console's Memory dropdown.",
                        "default": 3
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Residential proxy is strongly recommended — Meta aggressively rate-limits datacenter IPs. Apify RESIDENTIAL returns the highest success rate. Leave at the default unless you have a specific reason to change it.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    },
                    "runTag": {
                        "title": "Run tag",
                        "type": "string",
                        "description": "Custom label copied to every record's `__metadata.runTag`. Useful when you run the scraper on a schedule and want to group or filter dataset rows by run."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
