# Facebook Ads Library Scraper & Ad Monitor (`panix/facebook-ads-library-scraper`) Actor

Scrape the Meta Ad Library by keyword, Facebook Page or Ad Library URL: ad copy, media, start dates, days running, platforms, landing pages, EU reach and political spend. For competitor research, ad spying and brand monitoring, with only-new-ads alerts. No login, no browser.

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

## Pricing

from $0.30 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Facebook Ads Library Scraper & Ad Monitor

Scrape ads from the [Meta Ad Library](https://www.facebook.com/ads/library/) (Facebook, Instagram, Messenger, Threads, WhatsApp and Audience Network) by **keyword**, **Facebook Page** or **pasted Ad Library URL**. Each ad is one clean row: ad copy, headline, call to action, landing page, images, videos with their length, carousel cards, start date, **days running**, platforms, and spend, impressions and reach where Meta publishes them. Turn on **ad details** to add EU reach by country, age and gender, payer and beneficiary, and the advertiser's Instagram followers.

No Facebook login, cookies, Meta API token or browser. Runs start in seconds, results appear while the run is going, and you pay only for ads you receive.

### What you can do with it

- 🔎 **Search by keyword** in one or many countries at once, without building URLs: `"running shoes"` in US, GB and DE is one input.
- 🏢 **Get every ad of a competitor**: paste `https://www.facebook.com/nike`, a numeric Page ID, or an Ad Library page link.
- 🔗 **Paste any Ad Library URL**: every filter in it is kept (country, status, category, media type, platforms, languages, dates, sort order, exact phrase). Single-ad links (`?id=...`) return that one ad.
- 🏆 **Find winning ads**: keep only ads that have run for at least N days, or ads launched in the last 7 days.
- 🔁 **Monitor on a schedule**: name a watchlist and receive **only ads you have not received before**. Repeats are not charged.
- 🌍 **EU transparency data** (optional): reach by country, age and gender, targeted age and gender, payer and beneficiary, advertiser Instagram followers, likes and verification.
- 🧮 **Count ads** without downloading them: how many active ads does a brand or keyword have right now?
- 🤖 **AI-ready**: optional Markdown per ad for ChatGPT, Claude or a RAG pipeline, plus a summary per advertiser.

### Who uses it

- **Marketers and media buyers:** see which offers, hooks and creatives competitors run, and for how long.
- **Agencies:** audit a prospect's ads before a pitch, or list the businesses advertising on a keyword in a country.
- **E-commerce and dropshipping:** spot products and landing pages that advertisers keep paying to promote.
- **Brand monitoring:** a daily watchlist reports new ads that mention your brand or come from your competitors.
- **Researchers and journalists:** political and issue ads with spend, impressions and "paid for by", plus EU reach.
- **AI and data teams:** clean JSON or Markdown for dashboards, LLM analysis and RAG pipelines.

### Why this scraper

- **Every way in, in one run:** keywords, Facebook Pages (URL or ID) and pasted Ad Library URLs together, and each keyword in as many countries as you pick.
- **Pasted URLs keep every filter**, including dates, languages, platforms, sort order and exact phrase.
- **Filters for winning ads:** minimum days running, a launch-date window that is checked on every ad, one row per creative group, and one ad per advertiser.
- **Monitoring built in:** watchlists return only new ads on scheduled runs, and repeats are free.
- **More useful columns:** days running, video length, landing domain, UTM tags, carousel cards, political spend as numbers, optional EU reach and audience, and Markdown for AI.
- **Exact limits, no hard caps:** you get exactly the number of ads you ask for, from 1 to everything Meta returns, on every Apify plan.
- **Results while it runs**, plus a SUMMARY record that explains each source: totals, filters and errors.
- **Low price:** $0.50 per 1,000 ads on the Starter plan plus $0.003 per run. Failed sources, duplicates and filtered ads are free.

#### Coming from another Ad Library scraper?

| Problem people often run into | How this Actor handles it |
|---|---|
| Only Ad Library URLs are accepted, so you build URLs by hand | Type keywords, Page URLs or Page IDs, or paste URLs |
| One country per run | Pick several countries; each keyword runs in each one |
| The date filter returns ads that started long before your dates | `startDateFrom` and `startDateTo` mean "started running between", checked on every ad |
| No way to find long-running ("winning") ads | `minDaysRunning` |
| The same creative comes back many times | `skipDuplicateVersions`, plus de-duplication across all inputs |
| Daily runs charge again for ads you already have | A watchlist with `onlyNewAds`; repeats are not charged |
| Results appear only when the run ends | Ads are saved page by page as they arrive |
| Limits overshoot, or each search is capped | Exact limits, no caps |
| One blocked request fails the whole run | Retried from a new IP address, from the same results page |

**Reliability.** When Meta blocks a request, it is retried from a new IP address and continues from the same results page, so a block costs seconds instead of the run. Sources that still fail are listed in the run summary with a reason and are never charged. If Meta retires one of its internal query IDs, the Actor reads the current ones from Meta's own web app and carries on.

### How to use it

1. Click **Try for free** and open the **Input** tab.
2. Add **search terms**, **Facebook Pages** or **Ad Library URLs** (you can mix them).
3. Pick countries and filters, and set **Max ads per source**.
4. Click **Start**. Ads appear in the **Output** tab within seconds.
5. Download as JSON, CSV, Excel or HTML, or connect the results to your tools (see API and integrations below).

### Input examples

**Keyword search in three countries**

```json
{
  "searchTerms": ["running shoes", "protein powder"],
  "countries": ["US", "GB", "DE"],
  "maxAdsPerSource": 100
}
```

**Every active ad of your competitors**

```json
{
  "pageUrls": ["https://www.facebook.com/nike", "https://www.facebook.com/adidas", "15087023444"],
  "countries": ["ALL"],
  "activeStatus": "active",
  "maxAdsPerSource": 0
}
```

**Winning ads: video ads that have run for 30+ days, one per creative**

```json
{
  "searchTerms": ["skincare"],
  "countries": ["US"],
  "mediaType": "video",
  "minDaysRunning": 30,
  "skipDuplicateVersions": true,
  "maxAdsPerSource": 200
}
```

**New launches from the last 7 days, newest first**

```json
{
  "searchTerms": ["black friday"],
  "countries": ["US"],
  "startDateFrom": "7 days",
  "maxAdsPerSource": 300
}
```

**Daily competitor monitor: only ads you have not received yet** (save this as a [scheduled task](https://docs.apify.com/platform/schedules))

```json
{
  "pageUrls": ["https://www.facebook.com/nike"],
  "monitoringKey": "nike-daily",
  "onlyNewAds": true,
  "maxAdsPerSource": 500
}
```

**Paste an Ad Library URL** with any filters you set on facebook.com (political ads in the UK in this example), plus EU reach and advertiser details

```json
{
  "startUrls": [{"url": "https://www.facebook.com/ads/library/?active_status=all&ad_type=political_and_issue_ads&country=GB&media_type=all&q=energy&search_type=keyword_unordered"}],
  "includeAdDetails": true,
  "maxAdsPerSource": 50
}
```

**How many ads? Counts only**

```json
{
  "searchTerms": ["coffee", "yoga mat"],
  "pageUrls": ["https://www.facebook.com/shopify"],
  "countries": ["US"],
  "countOnly": true
}
```

### Output

One row per ad. A real row from a run on 29 October 2026 (with ad details on, media links shortened):

```json
{
  "adArchiveId": "1454592559544426",
  "adLibraryUrl": "https://www.facebook.com/ads/library/?id=1454592559544426",
  "isActive": true,
  "status": "ACTIVE",
  "startDate": "2026-05-13",
  "lastSeenDate": "2026-10-29",
  "daysRunning": 170,
  "pageId": "1917715138510680",
  "pageName": "Follow Your Legend",
  "pageUrl": "https://www.facebook.com/followyourlegend/",
  "pageCategories": ["Brand"],
  "pageLikeCount": 124078,
  "platforms": ["facebook", "instagram", "audience_network", "messenger", "threads"],
  "displayFormat": "VIDEO",
  "mediaType": "video",
  "bodyText": "AlpacaCloud is our custom-engineered blend of alpaca fiber and eucalyptus fiber—crafted to deliver the softest, most breathable socks you’ve ever worn. ...",
  "title": "Your feet deserve better than basic socks.",
  "ctaText": "Shop now",
  "ctaType": "SHOP_NOW",
  "linkUrl": "https://followyourlegend.com/pages/alpacacloud%C2%AE-socks-for-running",
  "linkDomain": "followyourlegend.com",
  "videos": [{"hdUrl": "https://video-xxc1-1.xx.fbcdn.net/...", "sdUrl": "https://video-xxc1-1.xx.fbcdn.net/...", "previewImageUrl": "https://scontent-xxc1-1.xx.fbcdn.net/...", "durationSeconds": 44}],
  "videoDurationSeconds": 44,
  "categories": ["UNKNOWN"],
  "containsAiGeneratedMedia": false,
  "mediaUrlsExpireAt": "2026-11-03T08:57:18Z",
  "sourceType": "searchTerms",
  "searchTerm": "running shoes",
  "searchCountry": "DE",
  "positionInSource": 6,
  "totalAdsInSource": 6993,
  "euTotalReach": 144059,
  "payer": "Follow Your Legend",
  "beneficiary": "Follow Your Legend",
  "advertiserInstagramUsername": "followyourlegend",
  "advertiserInstagramFollowers": 406804,
  "details": {
    "euReachByCountry": {"DE": 20548, "DK": 13194, "SE": 12541, "IT": 11373},
    "euReachByAgeGender": {"18-24": {"male": 12734, "female": 1645, "unknown": 978}},
    "audienceGender": "All", "audienceAgeMin": 18, "audienceAgeMax": 65
  },
  "scrapedAt": "2026-10-29T21:37:24Z"
}
```

Main fields:

| Field | What it is |
|---|---|
| `adArchiveId`, `adLibraryUrl` | Ad Library ID and a link to the ad |
| `status`, `isActive`, `startDate`, `endDate`, `lastSeenDate`, `daysRunning` | When the ad ran. `daysRunning` counts both the first and the last day |
| `pageId`, `pageName`, `pageUrl`, `pageLikeCount`, `pageCategories` | The advertiser |
| `bodyText`, `title`, `caption`, `linkDescription`, `ctaText`, `ctaType` | The ad copy. For dynamic ads (`{{product.name}}` templates) the real text is taken from the cards |
| `textVariations` | Other texts of the same ad (dynamic creative, carousel cards) |
| `linkUrl`, `linkDomain`, `utmParameters` | Landing page, its domain and its UTM tags |
| `imageUrls`, `videos`, `videoUrls`, `videoDurationSeconds`, `cards`, `cardsCount` | Creatives. `cards` holds each carousel card with its own text, link and media |
| `mediaUrlsExpireAt` | Meta's media links stop working at this time (usually a few days). Download files before then |
| `platforms`, `displayFormat`, `mediaType`, `categories` | Where it runs and what kind of ad it is |
| `spend`, `impressions`, `reachEstimate`, `currency`, `paidForBy` | For political and issue ads: Meta's ranges as text plus `lower` and `upper` numbers |
| `isNew`, `firstSeenDate` | With a watchlist: whether the ad is new since the last run |
| `details`, `euTotalReach`, `payer`, `beneficiary`, `advertiser*` | With ad details on |
| `searchTerm`, `searchCountry`, `sourceType`, `sourceUrl`, `positionInSource`, `totalAdsInSource` | Which input found the ad, its rank there, and the total Meta reports for that search |
| `markdown`, `raw` | Optional: Markdown summary, and Meta's original ad object (contact e-mails and phone numbers removed) |

The **Output** tab has ready-made views: Overview, Creatives, Spend & reach, Advertisers, Monitoring and Counts.

Each run also saves two records in its key-value store:

- **SUMMARY**: per source, the total ads Meta reports, ads delivered, pages read, why it stopped, ads left out by each filter, and the error if it failed.
- **ADVERTISERS**: per advertiser, the number of ads and active ads, platforms, media types, first and last start date, longest-running ad and top landing domains.

### Pricing

Pay per result: you pay for ads delivered to your dataset, nothing else.

| Apify plan | Per 1,000 ads | Ad details, per 1,000 ads |
|---|---|---|
| Free | $0.60 | $0.30 |
| Starter | $0.50 | $0.25 |
| Scale | $0.40 | $0.20 |
| Business and higher | $0.30 | $0.15 |

- **Run start:** $0.003 per run (covers start-up and empty scheduled checks).
- **Count rows** (`countOnly`): $0.001 per source.
- **Never charged:** failed sources, duplicates, ads removed by your filters, ads already delivered to your watchlist, and details that Meta did not return.
- **Examples (Starter):** 1,000 ads = $0.503. A daily monitor that finds 20 new ads = $0.013 per day. 1,000 ads with EU details = $0.753.
- Set a **maximum cost per run** in Run options; the run stops cleanly at that amount and keeps everything delivered so far.

### Good to know

- **What Meta shows:** active ads in every country. Meta keeps inactive ads mainly when they are about politics or social issues (7 years) or ran in the EU (1 year), so older commercial ads elsewhere may be missing from the public Ad Library, for every scraper.
- **Counts above 50,000** are reported by Meta as 50,000+ (`totalAdsInSource: 50001`, `totalIsLowerBound: true`).
- **Dates:** Meta's own date filter means "ran during these days". `startDateFrom` and `startDateTo` here mean "started running between these days", and every ad is checked.
- **Media links expire** after a few days (see `mediaUrlsExpireAt`), as in the Ad Library itself.
- **Speed:** about 30 ads every 3–5 seconds per source, and several sources run in parallel (`maxConcurrency`). In our tests, 9 sources with 60 ads each finished in 28 seconds.
- **Ad details** cost one extra request per ad, so runs take longer. EU reach exists only for ads delivered in the EU.

### API and integrations

**Python** (`pip install apify-client`)

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("panix/facebook-ads-library-scraper").call(run_input={
    "searchTerms": ["running shoes"],
    "countries": ["US", "GB"],
    "maxAdsPerSource": 100,
})
for ad in client.dataset(run.default_dataset_id).iterate_items():
    print(ad["pageName"], ad["daysRunning"], ad["adLibraryUrl"])
```

**JavaScript / Node.js** (`npm install apify-client`)

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('panix/facebook-ads-library-scraper').call({
    searchTerms: ['running shoes'],
    countries: ['US'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]?.pageName);
```

**cURL** (runs and returns the ads in one call, for runs up to 5 minutes)

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

**No-code tools**

- **n8n:** in the Apify node, run the Actor `panix/facebook-ads-library-scraper` with the input JSON, then read the run's dataset items.
- **Make:** Apify app → *Run an Actor* (wait until it finishes) → *Get Dataset Items*.
- **Zapier:** Apify app → *Run Actor* action, then fetch the dataset items of that run.
- **Google Sheets, Slack, webhooks:** under the Actor's **Integrations** tab.

**AI agents (MCP):** add `https://mcp.apify.com/?actors=panix/facebook-ads-library-scraper` to Claude, Cursor or any MCP client and ask, for example, "Which ads has Nike been running in Germany for more than 60 days?"

### FAQ

**Do I need a Facebook account, cookies or a Meta API token?**
No. The Actor reads the public Ad Library like a logged-out visitor.

**Why did I get fewer ads than `totalAdsInSource`?**
Your `maxAdsPerSource` limit, your filters (see `adsLeftOut` in SUMMARY), duplicates across inputs, or the end of Meta's results. Meta's total is an estimate.

**What happens when Meta blocks a request?**
It is retried on a new IP address from the same results page, up to `maxRetries` times. If a source still fails, the run continues with the other sources, the failure is listed in SUMMARY with an error code, and that source costs nothing.

**How does "only new ads" work?**
With a `monitoringKey`, the IDs of delivered ads are stored in your Apify account (key-value store `facebook-ads-library-watchlists`). With `onlyNewAds` on, later runs with the same key skip those ads and stop soon after they reach ads you already have. Delete the record to start over. Without a `monitoringKey`, `onlyNewAds` uses an automatic watchlist named after your inputs.

**Why is the watchlist name a secret field?**
A watchlist name can show which brands you track, so Apify stores it encrypted in saved inputs, tasks and schedules, and the Actor keeps it out of the run log. Through the API you send it as plain text, as before.

**Can I get ad spend for normal (non-political) ads?**
Meta publishes spend and impressions only for political and issue ads. For other ads, `daysRunning`, the number of versions (`collationCount`) and EU reach (with ad details) are the best public signals of how much an ad is used.

**Is it legal?**
The Meta Ad Library is a public transparency tool. This Actor collects only what it shows publicly and removes e-mail addresses and phone numbers from the raw data. Results can still include public names of people (for example, political advertisers), which can be personal data under the GDPR. Use the data for a legitimate purpose, and check Meta's terms and your local law. This Actor is not affiliated with or endorsed by Meta.

### Support

Found a problem or need a field? Open an issue on the **Issues** tab. Include the run ID; the SUMMARY record usually shows what happened.

# Actor input Schema

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

Words to search in the Meta Ad Library, for example <code>running shoes</code> or <code>shopify</code>. Each term is a separate search.

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

Every ad of these advertisers. Paste a Page URL (<code>https://www.facebook.com/nike</code>), a numeric Page ID (<code>15087023444</code>) or an Ad Library page link (<code>...view_all_page_id=...</code>).

## `startUrls` (type: `array`):

URLs copied from <a href='https://www.facebook.com/ads/library/' target='_blank'>facebook.com/ads/library</a>: a search, an advertiser view or a single ad (<code>?id=...</code>). Every filter in the URL is kept (country, status, ad type, media, platforms, languages, dates, sort, exact phrase).

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

Where the ads were shown. Choose several to search each country separately, or <b>All countries</b>.

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

Active ads are running now; inactive ads have stopped but are still in the library.

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

Special categories carry extra transparency data (spend, impressions, reach, 'paid for by').

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

Creative type. Video is double-checked on every ad.

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

Only ads that run on at least one of these platforms. Leave empty for all.

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

ISO 639-1 codes such as <code>en</code>, <code>es</code> or <code>de</code>. Leave empty for all languages.

## `searchMode` (type: `string`):

Broad matches ads with any of the words; exact phrase matches the words together.

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

Meta's order of results. With a start date filter or only-new mode, newest first is used automatically so the run can stop early.

## `startDateFrom` (type: `string`):

Only ads that started running on or after this day: <code>2026-10-01</code> or an age such as <code>7 days</code>, <code>2 weeks</code>, <code>3 months</code>. Checked on every ad.

## `startDateTo` (type: `string`):

Only ads that started running on or before this day (same formats).

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

Only ads that have run for at least this many days. Long-running ads are usually the profitable ones ('winning ads').

## `skipDuplicateVersions` (type: `boolean`):

Meta groups versions of the same ad (same creative and text). Turn on to get one row per group and pay for fewer rows.

## `oneAdPerAdvertiser` (type: `boolean`):

Keep only the first ad of each advertiser, for example to build a list of who advertises on a keyword.

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

For each search term and country, Page or URL. 0 = everything Meta returns.

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

Stop the whole run after this many ads. 0 or empty = no limit (your spending limit still applies).

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

One extra request per ad (charged as <b>ad details</b>): EU reach by country, age and gender, targeted age and gender, payer and beneficiary, advertiser Instagram followers, Page likes, category and verification.

## `countOnly` (type: `boolean`):

Return one row per source with the total number of ads Meta reports, without the ads.

## `includeMarkdown` (type: `boolean`):

A compact Markdown summary of each ad in the <code>markdown</code> field, ready for ChatGPT, Claude or a RAG pipeline.

## `includeRawData` (type: `boolean`):

The full Ad Library JSON in the <code>raw</code> field (contact e-mails and phone numbers removed).

## `monitoringKey` (type: `string`):

Any name, for example <code>nike-daily</code>. Ads delivered under this name are remembered in your account (key-value store <code>facebook-ads-library-watchlists</code>) and rows get <code>isNew</code> and <code>firstSeenDate</code>. Stored encrypted, because a watchlist name can show which brands you track.

## `onlyNewAds` (type: `boolean`):

Skip ads that an earlier run of the same watchlist already delivered. Skipped ads are not charged. Results are sorted newest first (unless you pick a sort order), so a run stops soon after it reaches ads you already have.

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

Pages 2+ of Ad Library results need residential IPs, which is the default. The first page, advertiser lookups and ad details use cheaper datacenter IPs automatically.

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

How many sources are scraped at the same time, each from its own IP address.

## `maxRetries` (type: `integer`):

A blocked or failed request is retried from a new IP address up to this many times.

## Actor input object example

```json
{
  "searchTerms": [
    "running shoes"
  ],
  "countries": [
    "US"
  ],
  "activeStatus": "active",
  "adType": "all",
  "mediaType": "all",
  "searchMode": "keyword_unordered",
  "sortBy": "relevance",
  "skipDuplicateVersions": false,
  "oneAdPerAdvertiser": false,
  "maxAdsPerSource": 30,
  "includeAdDetails": false,
  "countOnly": false,
  "includeMarkdown": false,
  "includeRawData": false,
  "onlyNewAds": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxConcurrency": 4,
  "maxRetries": 6
}
```

# Actor output Schema

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

Delivered ads. Failed sources and skipped ads are not in the dataset and are not charged.

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

Per-source status, total ads Meta reports, ads left out by each filter, and errors.

## `advertisers` (type: `string`):

Per-advertiser totals: ads, active ads, platforms, media types, first and last start date, top landing domains.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchTerms": [
        "running shoes"
    ],
    "countries": [
        "US"
    ],
    "maxAdsPerSource": 30,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("panix/facebook-ads-library-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchTerms": ["running shoes"],
    "countries": ["US"],
    "maxAdsPerSource": 30,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

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

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

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

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "running shoes"
  ],
  "countries": [
    "US"
  ],
  "maxAdsPerSource": 30,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call panix/facebook-ads-library-scraper --silent --output-dataset

```

## MCP server setup

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

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jlH43HEDe3iCbCfe5/builds/huzd7pNgPW0kLaDi6/openapi.json
