# Ad Library Scraper: Facebook, Google and Bing Ads (`agenttoolworks/ad-library-scraper`) Actor

Facebook Ads Library scraper plus Google Ads Transparency Center and Microsoft (Bing) Ad Library in one run: search a brand, keyword or domain and get every platform's ads in one table, with advertiser, payer, dates, reach, targeting and creative links.

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

## Pricing

from $0.40 / 1,000 ad returneds

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

### What is this Facebook Ad Library scraper?

This Actor is a **Facebook Ad Library scraper** (Meta Ad Library: Facebook, Instagram, Messenger, Threads) that also reads the **Google Ads Transparency Center** and the **Microsoft (Bing) Ad Library** in the same run. Search a brand, a keyword or an advertiser's domain once, or paste the **Meta Ad Library URL or Facebook Page** you already have, and get every platform's public ads back in **one table, one row format**: advertiser, ad text, creative images and videos, landing page, first and last day shown, reach and impressions, targeting, and a link to the ad in its library. For Meta ads shown in the EU, each row also carries **Meta's EU transparency data: people reached per country, payer, beneficiary and audience**.

**In short**

- **What you get**: Meta (Facebook, Instagram, Messenger, Threads), Google Ads Transparency Center and Microsoft (Bing) Ad Library ads from one search, one row per ad in the same format, with creatives, landing page, dates and, for Meta ads shown in the EU, reach per country, payer and beneficiary.
- **What it costs**: $0.50 per 1,000 ads on any platform ($0.40 on Apify Business plans), charged per ad delivered. A repeated ad, or one left out by `strictMatch`, is never charged.
- **Why this one** (same search, measured 2026-10-01 and 2026-10-05, prices read again 2026-10-13): Meta ads at $0.50 per 1,000 where curious_coder charges $0.75 and apify/facebook-ads-scraper $5.80; country, EU reach, payer and beneficiary filled on 100 of 100 ads where both leaders filled none; and Google and Microsoft ads in the same run, which neither offers.

Use it as a **competitor ad spy tool** without an account: no Facebook login, no Meta API token, no identity check.

![Facebook Ad Library scraper: one search in, Meta, Google and Microsoft ads out in one table](https://agenttoolworks.com/apify/adlibrary-overview-v2.png)

### What data can you extract from the ad libraries?

One row per ad, the same fields on every platform. Where a platform does not publish a field, it is `null`, never guessed.

| Ad data | Reach and targeting | Search and advertiser data |
|---|---|---|
| Ad ID and link to the ad in its library | Meta, EU ads: people reached in the EU (`euReach`) and per country | Advertiser name and ID |
| Title and body text (Meta, Microsoft; Google text ads where Google renders the text) | Impressions range (Google, Microsoft; Meta where it shows one) | `totalInLibrary`: how many ads the library reports for your search (Meta, Microsoft) |
| Every card of a carousel or dynamic ad (Meta) | Countries, with `countriesBasis` saying what they mean | `matchesQuery`: whether the row's own text shows your keyword |
| Creative image URLs, video URLs, preview URL | Reach per country: people reached (Meta), impressions with first and last day (Google), share of impressions (Microsoft) | Optional advertiser records (`maxAdvertisers`): the brand's footprint per platform |
| Landing page and display URL | Targeting: audience locations, ages and gender (Meta, EU ads); criteria used and excluded (Google, Microsoft) | |
| Call to action (Meta) | Payer and beneficiary (Meta, EU ads; Microsoft where named) | |
| Format, first shown, last shown, active today (Meta) | | |
| Publisher platforms: Facebook, Instagram, Audience Network, Messenger, Threads, Bing | | |

The fields follow what the EU's Digital Services Act requires very large platforms to publish in their ad repositories ([Regulation (EU) 2022/2065, Article 39](https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32022R2065)): the content, who it was presented for, who paid, the period, the targeting parameters and the recipients reached.

### Which ad libraries does it cover?

| Platform | What it reads | Countries |
|---|---|---|
| **Meta Ad Library** (Facebook, Instagram, Messenger, Threads, Audience Network) | The public Ad Library search page, logged out, in a real browser, and each ad's "See ad details" panel (EU transparency) | Every country the Ad Library offers; one search per country |
| **Google Ads Transparency Center** (Search, YouTube, Display, Shopping) | The Transparency Center's public pages, plus each ad's details | Every region; reach figures for the EEA |
| **Microsoft Ad Library** (Bing) | Microsoft's official public Ad Library API, no key | EEA only: Microsoft publishes only ads served in the European Economic Area |

### What can you use ad library data for?

- **Competitor ad research**: every ad a competitor runs on Facebook, Instagram, Google and Bing, in one export.
- **Creative inspiration and swipe files**: ad copy, images and videos, sorted by start date.
- **Market and campaign monitoring**: schedule a search and see which ads started or stopped since last week.
- **Agency reporting**: how many ads a brand runs, where, since when, with which landing pages.
- **Compliance and research**: who paid, which targeting, reach per EU country, for DSA and political ad research.
- **Data for AI agents and pipelines**: one predictable JSON row whatever the platform.

### How to scrape the Facebook Ad Library

1. Click **Try for free** (or **Start**) on this page and sign in to Apify.
2. Type a **Brand or keyword** (`nike`) or an **Advertiser domain** (`nike.com`), or paste **Meta Ad Library or Facebook Page URLs**.
3. Pick the **Platforms** (all three by default) and the **Countries** (`FR`, `DE`, `US`...; empty means all).
4. Set **Max ads per platform**. You pay per ad returned, so start small to look at the data.
5. Click **Start**. When the run finishes, open the **Output** tab, pick the **Ads** or **Reach by country (DSA)** view, and export as JSON, CSV, Excel or XML, or read it through the API.

![The Actor's input form in Apify Console: brand or keyword, advertiser domain, Meta Ad Library or Facebook Page URLs, platforms, countries, max ads per platform, dates, and the switches for active ads, reach details and keyword matching](https://agenttoolworks.com/apify/adlibrary-input-form-v2.jpg)

### Input

| Field | What it does |
|---|---|
| `query` | Brand or keyword. Meta and Microsoft search the ad text and the advertiser for it (when Microsoft's keyword search does not answer, Microsoft returns the ads of the advertisers named like it, and says so). Google has no text search: the Actor finds the Google advertisers whose name contains the word (`nike` finds "Nike, Inc." and "NIKE SRL") and returns their ads. |
| `domain` | An advertiser's website, for example `nike.com`. Google returns the ads that point to it; Meta and Microsoft use it as the keyword when `query` is empty. |
| `startUrls` | Meta Ad Library search URLs (the keyword, country, active status, ad type, media type and dates set on Meta's page are kept), a page's ads URL (`view_all_page_id=`), Facebook Page URLs (`facebook.com/nike`, `profile.php?id=`) or page IDs. Each is its own Meta search, up to `maxResultsPerPlatform` ads. A page alias is resolved to its page ID through the library itself. Up to 20 per run. |
| `platforms` | `meta`, `google`, `microsoft`. All three by default. |
| `countries` | Two-letter codes. Empty means all countries. Meta runs one search per country; Microsoft is skipped when no requested country is in the EEA. |
| `maxResultsPerPlatform` | Stop after this many ads on each platform (default 100, up to 1,000). |
| `startDate`, `endDate` | `YYYY-MM-DD`. Only ads shown in that window, on every platform. |
| `activeOnly` | Meta only: ads running today (default). Turn off to include stopped ads. |
| `includeDetails` | One more request per ad for the transparency details (default on). Meta: EU reach per country, payer, beneficiary, audience. Google: impressions per country, dates, targeting, and the text of text ads where Google renders it. Microsoft: impressions per country, dates, targeting, payer. Off gives a fast list of creatives. |
| `strictMatch` | Meta: keep only ads whose own text (advertiser, title, body, cards, link) shows the keyword (default on). Meta also matches words inside images and videos; those ads are left out before they are returned or charged, and the Actor reads further to fill your request. Off keeps them, flagged `matchesQuery: false`. |
| `maxAdvertisers` | Optional advertiser records per platform (default 0: off). Stored in the key-value store, not the ads dataset. |
| `proxy` | Meta only: `none` (default, the cheapest, read 1,000 Meta ads in our tests), `datacenter` or `residential` (Apify Proxy). |

Example: every Nike ad shown in France on the three platforms, 20 per platform (60 ads in 22.5 seconds on Apify, 2026-10-02).

```json
{
  "query": "nike",
  "countries": ["FR"],
  "platforms": ["meta", "google", "microsoft"],
  "maxResultsPerPlatform": 20,
  "includeDetails": true
}
```

Example: Meta only, 1,000 ads, one country.

```json
{
  "query": "nike",
  "countries": ["FR"],
  "platforms": ["meta"],
  "maxResultsPerPlatform": 1000
}
```

Example: paste what you already have in Meta's Ad Library, and a brand's Facebook Page.

```json
{
  "startUrls": [
    { "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=FR&q=le%20slip%20fran%C3%A7ais&search_type=keyword_unordered&media_type=all" },
    { "url": "https://www.facebook.com/nike" }
  ],
  "maxResultsPerPlatform": 30
}
```

Measured locally on 2026-10-05: 26 ads for the first URL (Meta reported 39; the 13 left out by `strictMatch` were other advertisers' "non slip" yoga mat and watch ads) and 30 for the Nike page (resolved to page 15087023444), 20 seconds in all. Google and Microsoft are reported as skipped, since URLs are Meta searches.

### Output

The dataset holds **ads only**, one row per ad, with two ready-made views in Apify Console and in the API:

- **Ads**: one row per ad, all platforms in one table.
- **Reach by country (DSA)**: one row per ad and country, with the people reached (Meta, EU and UK), impressions (Google, Microsoft) or share of impressions (Microsoft) each platform publishes, with details on.

**No duplicates**: an ad is returned and charged once per run, keyed by platform and ad ID across pages, countries and searches (Microsoft's list repeats ads across pages; the run summary says how many repeats were skipped).

**Countries**: `countriesBasis` says what `countries` means. `reach` means the platform reports delivery in those countries (Google, Microsoft, and Meta when its EU or UK transparency data was read). `search_filter` means Meta listed the ad when its library was filtered on that country, which is how Meta defines "shown in" a country, with no per-country figures.

**Advertiser records** (opt-in with `maxAdvertisers`) are in the run's key-value store, record `ADVERTISERS`, so they never mix with ad rows in a view.

![Ads view of a real cloud run in Apify Console: Meta ads for the search "nike" in France, with creative, advertiser, title, text, dates, countries, EU reach, payer, beneficiary, landing page and the keyword check](https://agenttoolworks.com/apify/adlibrary-ads-view-v2.jpg)

![Reach by country view of the same run: one row per Meta ad and country, with the people reached in that country](https://agenttoolworks.com/apify/adlibrary-reach-view-v2.jpg)

A **Meta** ad row from the cloud run shown above (build 0.1.8, search `nike`, France, 2026-10-05; image URLs, cards and countries shortened):

```json
{
  "rowType": "ad",
  "platform": "meta",
  "adId": "1870984290951787",
  "adLibraryUrl": "https://www.facebook.com/ads/library/?id=1870984290951787",
  "advertiserId": "15087023444",
  "advertiserName": "Nike",
  "payer": "NIKE, Inc.",
  "beneficiary": "NIKE, Inc.",
  "firstShown": "2026-09-02",
  "lastShown": "2026-10-04",
  "isActive": true,
  "format": "dynamic",
  "title": "Nike Primary",
  "body": "Get the gear that's up for it all. Any time. Anywhere.",
  "linkUrl": "https://www.nike.com/",
  "displayUrl": "http://nike.com/",
  "ctaText": "Shop now",
  "imageUrl": "https://scontent-iad6-1.xx.fbcdn.net/v/t39.35426-6/793144872_3319523978256315_8997515453029015143_n.jpg?...",
  "cards": [
    { "title": "Nike Primary", "body": "Get the gear that's up for it all. Any time. Anywhere.", "linkUrl": "https://www.nike.com/gb/t/primary-mens-dri-fit-short-sleeve-versatile-top-RSKW7H/DV9831-100", "displayUrl": "nike.com", "imageUrl": "https://scontent-iad6-1.xx.fbcdn.net/...", "videoUrl": null }
  ],
  "publisherPlatforms": ["FACEBOOK", "INSTAGRAM", "AUDIENCE_NETWORK", "MESSENGER", "THREADS"],
  "countries": ["DE", "IT", "FR", "ES", "NL", "PL", "GB"],
  "countriesBasis": "reach",
  "euReach": 7231158,
  "reachByCountry": [
    { "country": "DE", "countryReach": 1290022 },
    { "country": "IT", "countryReach": 1167694 }
  ],
  "audience": { "locations": ["Italy", "Netherlands", "Spain", "Poland", "France", "Germany"], "excludedLocations": [], "ageMin": 18, "ageMax": 65, "gender": "All" },
  "matchesQuery": true,
  "totalInLibrary": 6632,
  "query": "nike",
  "scrapedAt": "2026-10-05T00:05:49.959Z"
}
```

A **Google** text ad row from a local run (`nike`, France, 2026-10-05), with details on (preview URL and country list shortened, `null` fields left out):

```json
{
  "rowType": "ad",
  "platform": "google",
  "adId": "CR08027505669651300353",
  "adLibraryUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233/creative/CR08027505669651300353?region=FR",
  "advertiserId": "AR16735076323512287233",
  "advertiserName": "Nike, Inc.",
  "advertiserCountry": "US",
  "firstShown": "2022-06-28",
  "lastShown": "2026-06-23",
  "format": "text",
  "title": "Worry Free Shopping",
  "body": "Rock your game-ready look inspired by your favorite team. Explore new Nike fan gear now!",
  "displayUrl": "nike.com",
  "imageUrl": "https://tpc.googlesyndication.com/archive/simgad/11154944259192068658",
  "previewUrl": "https://displayads-formats.googleusercontent.com/ads/preview/content.js?...",
  "countries": ["GR", "ES", "MX", "US", "DE", "FR", "PL", "CA", "IT"],
  "countriesBasis": "reach",
  "impressionsMin": 0,
  "impressionsMax": 1000,
  "reachByCountry": [
    { "country": "GR", "countryImpressionsMin": 0, "countryImpressionsMax": 1000, "countryLastShown": "2026-03-14" },
    { "country": "ES", "countryImpressionsMin": 0, "countryImpressionsMax": 1000, "countryLastShown": "2025-11-27" }
  ],
  "targeting": { "included": ["demographics", "location", "contextual_signals"], "excluded": ["location"] },
  "matchesQuery": true
}
```

A **Microsoft (Bing)** ad row from the same run (fields left out when `null`; every real row carries every key):

```json
{
  "rowType": "ad",
  "platform": "microsoft",
  "adId": "71124892377247",
  "advertiserId": "4295002191",
  "advertiserName": "Groupe COURIR",
  "firstShown": "2023-06-03",
  "lastShown": "2026-09-30",
  "format": "text",
  "title": "Baskets & Vêtements Streetwear NIKE pour - Tendances 2026",
  "body": "Shorts pour Homme Nike - Découvrez les meilleurs prix sur le site courir.com. Shorts pour Homme Nike - Les plus grandes marques sur le site courir.com. Profitez-en !",
  "linkUrl": "https://www.courir.com/fr/c/homme/marque/nike/?prefn1=subTypology&prefv1=SHORT",
  "displayUrl": "courir.com",
  "publisherPlatforms": ["BING"],
  "countries": ["FR", "LU"],
  "impressionsMin": 1000000,
  "impressionsMax": 2500000,
  "reachByCountry": [
    { "country": "FR", "countrySharePercent": 100 },
    { "country": "LU", "countrySharePercent": 0 }
  ],
  "targeting": { "included": ["location", "microsoft_audiences", "advertiser_audiences"], "excluded": ["location"] }
}
```

An **advertiser** record (Google, from the 2026-10-02 cloud run; opt-in with `maxAdvertisers`, stored in the key-value store record `ADVERTISERS`):

```json
{
  "rowType": "advertiser",
  "platform": "google",
  "advertiserId": "AR16735076323512287233",
  "advertiserName": "Nike, Inc.",
  "advertiserCountry": "US",
  "advertiserVerified": null,
  "adsInLibraryMin": 9000,
  "adsInLibraryMax": 10000,
  "adsReturned": 20,
  "advertiserUrl": "https://adstransparency.google.com/advertiser/AR16735076323512287233",
  "query": "nike"
}
```

That cloud run returned 60 ads (20 per platform) and 9 advertiser records in 22.5 seconds.

#### Run summary

The run's key-value store holds a `SUMMARY` record with one status per platform: `ok`, `partial` (fewer ads than asked while the library shows more, with the reason), `skipped` (for example Microsoft with no EEA country) or `failed`, plus how many ads Meta reports for the search, how many ads `strictMatch` left out, how many repeats were skipped, how many EU transparency panels were read, and how many requests each platform took. A short result is never silent.

### Limits worth knowing before you run it

- **Meta, logged out, shows the first 30 results of a search and refuses further pages.** The Actor goes past that by walking back through start dates with the page's own "most recent" order: the top 30 by impressions first, then up to 30 newer ads per page load, day by day. Measured on Apify: 1,000 Nike ads in France in a 139-second run. Its one blind spot: **a start day with more than 30 new ads shows only its first 30**, and the summary says so when it makes the result short.
- **Meta reach, payer, beneficiary and audience are published by Meta for ads shown in the EU (and UK reach)**, through each ad's "See ad details" panel, which the Actor reads logged out, one request per ad. Ads shown only outside the EU and UK have none: Meta does not publish it. Spend is not published for commercial ads. In a cloud run of this build, 100 of 100 Nike ads searched in France had EU reach, payer and beneficiary (local runs: 300 of 300 Nike, 100 of 100 Adidas); a page searched in all countries had it on 2 of 30.
- **Meta keyword matches you cannot see**: Meta also matches words inside images and videos, and its "most recent" pages beyond the first 30 ads hold many such matches (48 of 100 Nike FR rows in a local run with `strictMatch` off). `strictMatch` (default) leaves them out before charging, so a small brand can return fewer ads than Meta's count: `le slip français` returned 26 of the 39 Meta reported, the other 13 being "non slip" yoga mats and a watch shop.
- **Google ad text** is read where Google renders the ad as text (its local text ads): 36 of 83 Nike text ads in a local run. Text ads that Google archives as an image carry their text only in the image (the row links it). Google publishes **no landing URL**, only the display domain, so `linkUrl` is `null` on Google rows. Google's preview host answers HTTP 429 at about one request a second, so text reading is paced and adds about a second per text ad.
- **Google has no keyword search**: `query` matches advertiser names as whole words, so `nike` can also match a person's account named "Nike Klara". Advertisers are ranked by ad count and capped by `maxAdvertisers`. Use `domain` for an exact brand.
- **Microsoft covers the EEA only**, because Microsoft publishes only ads served there. Its list repeats ads across pages (64 repeats skipped on a 100-ad read); each ad is returned and charged once.
- **Microsoft's keyword search is slow on Microsoft's side.** On 2026-10-13 a keyword search page took 20 to 130 seconds, and some searches (`booking.com`) never answered, from Apify and on Microsoft's own Ad Library site alike. When the first page does not answer within about a minute, the Actor reads the ads of the Microsoft advertisers named like your keyword instead (for `booking.com`: Booking.com B.V.), with Microsoft's own country filter, and the run summary marks Microsoft `partial` with that reason: these are that brand's own ads, not every ad that mentions the word.
- **Microsoft put a firewall in front of its Ad Library on 2026-10-13.** It refuses scripts that announce themselves; the Actor reads the API with the request a visitor's browser sends, and if the firewall ever refuses that, it moves the rest of the search to a real browser. If that is refused too, Microsoft is reported `failed` with the firewall's answer as the reason, never as an empty success.
- **Microsoft rate-limits repeated reads (HTTP 429).** The Actor paces its requests and retries, but when Microsoft keeps refusing, it stops and says so: a 100-ad Microsoft read on Apify returned 91 ads in a 160-second run, status `partial`, reason "Rate limited (HTTP 429)". Smaller reads (10 to 20 ads) were not throttled in our cloud runs.
- **Image and video URLs depend on the format.** Meta video ads have `imageUrl` empty: the video file is in `videoUrls` and its poster image in `previewUrl` (21 of 100 rows in the Nike run above; the 79 others carry `imageUrl`). Google video ads, and some Google image ads, carry only `previewUrl`, Google's preview script, with no direct image or video file. Microsoft ads are text ads, with no media.

### How it compares with the Meta leaders (measured)

Same input on every Actor: keyword `nike`, country FR, active ads, 100 ads, Meta only. Every figure is an Apify cloud run: the leaders' on 2026-10-01 (runs WifMYQ8g9j4Is7WK4 and aQPqwfH2TxYFBYqP6, from our competitor teardown), ours on 2026-10-05 on build 0.1.8 with EU details on (run 1Rop20lfahxqPOS4D, no proxy). Store prices are the FREE-tier list prices of 2026-10-01.

| | curious_coder/facebook-ads-library-scraper | apify/facebook-ads-scraper | This Actor |
|---|---|---|---|
| Price per 1,000 Meta ads | $0.75 + $0.00005 per run | $5.80 | $0.50 |
| Ads returned of 100 asked | 100 | 100 | 100 |
| Duplicate rows | 0 | 0 | 0 |
| Rows whose own text shows "nike" | 84 of 100 | same 100 ads as curious_coder | 100 of 100 (`strictMatch` left out 75 that did not) |
| Countries filled | 0% | 0% | 100% |
| EU reach, payer, beneficiary | 0% | 0% | 100% |
| Body text | 94% | 94% | 93% (the rest have no body in Meta's data) |
| Media | 100% | 100% | 100% (79 image, 21 video) |
| Landing link | 99% | 99% | 96% (the rest have no link in Meta's data) |
| Start and end dates | 100% | 100% | 100% |
| Meta's total for the search on each row | yes | not measured | yes (`totalInLibrary`) |
| Ad Library and Page URLs as input | yes | yes | yes |
| Run time, 100 Meta ads | 38 s | 77 s | 45 s with EU details for every ad (Meta read in 21.4 s) |
| Google and Microsoft ads in the same run | no | no | yes |

The three Actors do not return the same ads after the first 30: the leaders read Meta's default ranking, which the logged-out page serves only for its first page, and this Actor walks start dates. Body, link and media shares are therefore over different ads.

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

Pay per event, no subscription, platform usage included:

| Event | Price |
|---|---|
| Ad returned, any platform | **$0.50 per 1,000 ads** ($0.0005 each) |
| Advertiser record returned (only if you set `maxAdvertisers`) | **$0.003 per advertiser row** |
| Run start | $0.00005 |

Examples:

- **1,000 Meta ads**: $0.50, EU transparency included.
- **100 Meta ads** (the comparison run above): $0.05.
- **60 ads on three platforms**: $0.03.
- A repeated ad, or an ad left out by `strictMatch`, is never charged.
- **Apify's free plan** includes $5 of monthly usage ([apify.com/pricing](https://apify.com/pricing)), enough for about **10,000 ads** a month.

Set a maximum cost per run in the run options and the Actor stops cleanly when it is reached.

### Use the Actor through the Apify API

Run it and get the ads in one HTTP call (replace `YOUR_APIFY_TOKEN`, from **Settings > API & Integrations** in Apify Console):

```bash
curl -X POST "https://api.apify.com/v2/acts/agenttoolworks~ad-library-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "nike", "countries": ["FR"], "maxResultsPerPlatform": 50}'
```

Node.js, with the official [`apify-client`](https://docs.apify.com/api/client/js/):

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('agenttoolworks/ad-library-scraper').call({
    query: 'nike',
    countries: ['FR', 'DE'],
    platforms: ['meta', 'google', 'microsoft'],
    maxResultsPerPlatform: 100,
});
const { items: ads } = await client.dataset(run.defaultDatasetId).listItems();
console.log(ads.map((ad) => [ad.platform, ad.advertiserName, ad.firstShown, ad.euReach, ad.title]));
```

Python, with the official [`apify-client`](https://docs.apify.com/api/client/python/):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("agenttoolworks/ad-library-scraper").call(
    run_input={"query": "nike", "countries": ["FR"], "platforms": ["meta"], "maxResultsPerPlatform": 200}
)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["advertiserName"], row["firstShown"], row["euReach"], row["body"])
```

The **API** tab on this page has ready-made snippets for every language and endpoint.

### FAQ

#### Do I need a Facebook account or a Meta API token?

No. The Actor reads the Ad Library the way a logged-out visitor sees it. Meta's own Ad Library API requires a Facebook account and an identity confirmation, and it returns commercial ads only when they reached the EU; the public page shows every active ad.

#### Can I get ads from the United States or other countries outside the EU?

On Meta and Google, yes: set the country (`US`) or leave countries empty. Microsoft publishes only ads served in the EEA. Reach and targeting figures are published for the EU and EEA (and the UK on Meta), so rows from elsewhere carry dates, creatives and landing pages without them.

#### Can I get every ad an advertiser runs?

Up to 1,000 per platform per run. On Meta, paste the advertiser's Facebook Page URL to read its page only; a brand with more than 30 new ads on a single day loses the rest of that day (see the limits above). On Google, use `domain` for the exact advertiser.

#### Can I get inactive ads?

On Meta, turn off **Active ads only**: Meta keeps ads that ran in the EU for a year after they stop, and political ads for seven years. On Google and Microsoft, use **Shown from** and **Shown until**.

#### How fast is it?

Measured on Apify with the current build (0.1.8, 2026-10-05): 100 Meta ads with the EU transparency panel of every ad in a 45-second run (Meta read in 21.4 seconds); the default input (10 ads per platform, three platforms, details on) in a 34-second run. Earlier builds on Apify (2026-10-02): 60 ads with details on three platforms in 22.5 seconds; 1,000 Meta ads without EU details in a 139-second run; 500 in 69 seconds. Google with details takes about one second per ad. Microsoft did too until 2026-10-12; since 2026-10-13 its servers answer much more slowly (keyword search pages of 20 to 130 seconds or none at all, details of 10 to 15 seconds each), so the Actor gives Microsoft at most 3.5 minutes plus 3 seconds per ad found in a run, then returns what it has, marked `partial` with the reason. On build 0.1.13 (2026-10-13): the default input in an 85-second run with 10 ads from each platform; 50 Booking.com ads shown in Germany, every one with its details, in a 266-second run; asked for 1,000 Nike ads, Microsoft gave 323 (318 with details) before the allowance ran out, in a 20-minute run. Microsoft also throttles repeated reads (HTTP 429); the Actor waits and retries.

#### Can I use it with Make, Zapier, n8n or Google Sheets?

Yes, through Apify's integrations: the dataset works with every Apify integration, and a webhook can fire when a run finishes. Save your input as a task and schedule it to follow a competitor every week.

#### Can AI agents use it through MCP?

Yes. Apify's hosted MCP server exposes Store Actors to MCP clients such as Claude or Cursor: `https://mcp.apify.com?tools=agenttoolworks/ad-library-scraper`.

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

The Actor reads only what the ad libraries show to any visitor without logging in: ads and the businesses behind them, which the platforms publish to meet their transparency obligations. It never logs in, uses no account and collects no data about the people who saw the ads. Each platform's terms restrict automated collection or reuse in some form; how you use the data is your responsibility.

#### Something is missing or broken?

Open an issue in the **Issues** tab: we read every one.

### Other Actors by AgentToolWorks

- [Shopify & WooCommerce Scraper and Price Tracker](https://apify.com/agenttoolworks/shopify-woocommerce-scraper): every product of any Shopify or WooCommerce store, with variants, barcodes and stock, plus price and stock change tracking.
- [LinkedIn Jobs and Indeed Scraper](https://apify.com/agenttoolworks/linkedin-indeed-jobs-scraper): public job listings of both boards in one row format.
- [Job Scraper for Greenhouse, Lever, Ashby & Workable (JobsRadar)](https://apify.com/agenttoolworks/jobsradar-multi-board-job-search): open roles from the public boards of seven applicant tracking systems, deduplicated into one list.
- [Google Maps Scraper](https://apify.com/agenttoolworks/google-maps-places-scraper): every place inside a city's real boundary, with phone, website, rating, review count, opening hours and emails.
- [Google Trends Scraper](https://apify.com/agenttoolworks/google-trends-scraper): interest over time, by region and related queries for terms and comparisons, plus each country's Trending now list.

### Learn more

- [What this Facebook Ad Library scraper returns, platform by platform](https://agenttoolworks.com/scrapers/facebook-ad-library-scraper)
- [How to scrape the Facebook Ad Library: what the page shows logged out, and how to go past 30 ads](https://agenttoolworks.com/blog/how-to-scrape-the-facebook-ad-library)

Built by [AgentToolWorks](https://agenttoolworks.com). Not affiliated with Meta, Google or Microsoft.

# Actor input Schema

## `query` (type: `string`):

What to search. Meta and Microsoft search the ad text and advertiser for this keyword (when Microsoft's keyword search does not answer, Microsoft returns the ads of the advertisers named like it, and the run summary says so). Google has no text search: the Actor finds the Google advertisers whose name contains this word (for example 'nike' finds 'Nike, Inc.' and 'Nike Retail BV') and returns their ads. Optional when startUrls are set.

## `domain` (type: `string`):

Optional. An advertiser's website, for example nike.com. Google returns the ads that point to this domain; Meta and Microsoft search for it as a keyword when no brand or keyword is set.

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

Optional. Paste Meta Ad Library search URLs (every filter you set on Meta's page is kept: keyword, country, active status, ad type, media type, dates), a page's ads URL (view_all_page_id=...), Facebook Page URLs (facebook.com/nike) or page IDs. Each is its own Meta search, up to the max ads below. Meta only: to search Google and Microsoft too, also set a brand or keyword.

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

Which ad libraries to search. All three by default; Meta only when you give startUrls and no brand or keyword.

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

Two-letter country codes (FR, DE, US...). Empty means all countries. Meta runs one search per country; Microsoft only covers the EEA, so it is skipped when no requested country is in the EEA.

## `maxResultsPerPlatform` (type: `integer`):

Stop after this many ads on each platform. You are charged per ad returned.

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

Optional, YYYY-MM-DD. Only ads shown on or after this day, on every platform.

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

Optional, YYYY-MM-DD. Only ads shown on or before this day, on every platform.

## `activeOnly` (type: `boolean`):

Meta only: return ads running today. Turn off to include ads that stopped (Meta keeps ads shown in the EU for a year after they stop, and political ads for seven years).

## `includeDetails` (type: `boolean`):

One extra request per ad for the transparency details. Meta: EU reach (people reached, per country), payer, beneficiary and audience (locations, ages, gender), for ads shown in the EU. Google: impressions per country, first and last day shown, targeting criteria, and the text of text ads where Google renders it. Microsoft: impressions per country, dates, targeting, payer. Slower; turn off for a fast list of creatives.

## `strictMatch` (type: `boolean`):

Meta also matches your keyword inside images and videos, and in its 'Most recent' pages beyond the first 30 ads about half of the matches do not show the keyword anywhere in their text. On (the default), such ads are left out before they are returned or charged, and the Actor reads further to fill your request. Off, they are kept and flagged with matchesQuery false.

## `maxAdvertisers` (type: `integer`):

Optional, off by default. Also return up to this many advertisers matching your search per platform (ID, name, country, ad count where published): the brand's footprint across platforms. They are stored in the run's key-value store (record ADVERTISERS), not in the ads dataset, and charged per advertiser.

## `proxy` (type: `string`):

Meta only. No proxy is the fastest and cheapest, and read 1,000 Meta ads in our tests. With a proxy, a page Meta refuses is retried from a new IP. Residential costs about 12 times more in Apify usage. Google and Microsoft always answer directly.

## Actor input object example

```json
{
  "query": "nike",
  "domain": "nike.com",
  "startUrls": [
    {
      "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=FR&q=nike&search_type=keyword_unordered&media_type=all"
    }
  ],
  "platforms": [
    "meta",
    "google",
    "microsoft"
  ],
  "countries": [
    "FR",
    "DE"
  ],
  "maxResultsPerPlatform": 10,
  "activeOnly": true,
  "includeDetails": true,
  "strictMatch": true,
  "maxAdvertisers": 0,
  "proxy": "none"
}
```

# Actor output Schema

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

No description

## `reach` (type: `string`):

No description

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

No description

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

No description

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "query": "nike",
    "platforms": [
        "meta",
        "google",
        "microsoft"
    ],
    "countries": [
        "FR"
    ],
    "maxResultsPerPlatform": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("agenttoolworks/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 = {
    "query": "nike",
    "platforms": [
        "meta",
        "google",
        "microsoft",
    ],
    "countries": ["FR"],
    "maxResultsPerPlatform": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("agenttoolworks/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 '{
  "query": "nike",
  "platforms": [
    "meta",
    "google",
    "microsoft"
  ],
  "countries": [
    "FR"
  ],
  "maxResultsPerPlatform": 10
}' |
apify call agenttoolworks/ad-library-scraper --silent --output-dataset

```

## MCP server setup

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