# Facebook Ads Library Scraper: Ads, Transcripts & Google Ads (`ntriqpro/facebook-ads-library-scraper`) Actor

Facebook and Instagram Ad Library scraper, $2.50 per 1,000 ads: every ad, plus what others skip. Video transcripts, text inside image ads, every landing page and the same advertiser's Google ads, with an advertiser verdict. Batch input, pay per result.

- **URL**: https://apify.com/ntriqpro/facebook-ads-library-scraper.md
- **Developed by:** [Daniel Carter](https://apify.com/ntriqpro) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 ad-founds

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: Ads, Video Transcripts, Image Text & Google Ads

Scrape the public Facebook and Instagram **Ad Library** (Meta Ad Library) for any advertiser, page URL, page ID or keyword. You get every ad for **$2.50 per 1,000 ads**, plus the layers other scrapers leave to you: the **landing page behind each ad**, the **same advertiser's Google ads**, **text printed inside image ads**, **video ad transcripts**, and one **advertiser verdict row** (scaling, testing, steady, dormant) that says why.

No login, no cookies, no setup: paste an advertiser and run.

### Free vs Paid

| | Free plan | Paid plan |
|---|---|---|
| Advertisers or searches per run | 1 | up to 50 |
| Ads per advertiser | 20 | up to 5,000 (default 200) |
| Landing page, Google ad, image text, transcript and AI creative analysis rows | 1 sample row of each layer (the Google ads sample can be missing: the free plan asks Google without the proxy and may be refused), the rest counted as locked | every row |
| Date range and "only new since my last run" | locked (paid plans only) | yes |
| Price | list price x 1.5 ($3.75 per 1,000 ads) | list price ($2.50 per 1,000 ads, 33% cheaper per row) |

A free run ends with `free-plan-locked` rows (for example `20 of 73 ads shown`) and one `free-plan-preview` row that says what the same input returns on a paid plan, with an estimate in dollars: the total the same input costs on a paid plan (`paidTotalUsd`) next to what the free run cost (`freeRunUsd`). The free plan also reads one sample video ad (the sample video transcript) even when `transcripts` is off; it is charged as a normal `video-transcribed` event at the free price. Free runs finish as SUCCEEDED; nothing looks like an error.

### What you pay (pay per event)

List price, what BRONZE and every higher plan pays. The free plan pays 1.5x.

| Event | Charged for | Price |
|---|---|---|
| `run-started` | one run (also when the input has nothing to look up) | $0.005 |
| `ad-found` | one ad row, all fields, image and video URLs included | $0.0025 (= $2.50 per 1,000 ads) |
| `advertiser-profiled` | one advertiser summary + verdict row | $0.005 |
| `landing-page-checked` | one distinct landing URL that answered (any HTTP status) | $0.004 |
| `google-ad-found` | one Google Ads Transparency Center creative of the advertiser's domain | $0.002 |
| `image-text-read` | one ad image that carries readable text | $0.001 |
| `video-transcribed` | one video ad that has speech | $0.015 |
| `ad-creative-analyzed` | one distinct ad creative read by an AI model (the same text and image text is read and charged once) | $0.003 |

Not charged: notice rows, duplicate ads, pictures without text, videos without speech, and anything we could not fetch (our side). A page that answered with 403 or 404 *is* an answer and is a row.

Example, 50 ads of one advertiser with the default layers: $0.005 + 50 x $0.0025 + $0.005 = **$0.135**, plus landing pages, Google ads and image texts that were found.

### What you get

1. **Collect**: every ad of an advertiser or keyword from the logged-out Ad Library (US by default, any country list), with creative text, headline, call to action, dates, run days, platforms, spend and reach when the library shows them, EU data, paid-for-by, report counts, image and video URLs. Creative files are linked, never copied.
2. **Dedupe**: one row per ad id, one row per landing URL (click-tracking parameters removed), one row per creative file.
3. **Enrich** (switch layers on or off with `enrich`):
   - `landingPages`: final URL, HTTP status, title, and product name and price when the page sells something (not only shop pages).
   - `googleAds`: the same advertiser's ads in Google Ads Transparency Center (format, first and last shown, advertiser, preview link).
   - `imageText`: the text printed on image ads (OCR, confident words only).
   - `transcripts`: speech in video ads (off by default; slower).
   - `creativeAi`: one row per distinct creative with `hookType`, `offer`, `targetAudience`, `angle`, `emotion`, `claims` and `language`, read by an AI model from the ad text, headline, button, image text, video speech and landing page. The same creative (same text and image text) is read and charged once. A creative with nothing to read, or a model failure, adds no row and no charge.
4. **Judge**: one `advertiser` row: active ads reported and collected, new ads in the last 30 days, longest-running ad, formats, platforms, top calls to action and landing domains, whether the advertiser also runs Google ads, and a `verdict` with a `verdictBasis` sentence. With `creativeAi` on, the row also carries `topHooks` (top three hook types and their share), `dominantOffer` (the offer that appears in at least two ads, otherwise null) and `audiences`, counted from the readings.

Every row carries `sourceUrl`, `checkedAt`, `confidence` and `basis`, so a person or an AI agent can see where it came from and why.

### Input

- `pageUrls` (required): one per line. A Meta Ad Library URL, a Facebook page URL (`facebook.com/nike`), a page ID, or a search term.
- `maxAdsPerTarget`: default 200.
- `enrich`: extra layers; default landing pages, Google ads, image text and AI creative analysis.
- Advanced: `countries`, `adStatus`, `maxTranscripts`, `adsAfter`, `adsBefore`, `onlyNewSinceLastRun`, `proxyConfiguration`.

The run starts on its own network and switches to the residential proxy when Meta rate-limits it. Keep the proxy switched on (default).

### Example rows

```json
{"rowType": "ad", "adArchiveId": "1016451784037642", "pageName": "Nike", "isActive": true, "startDate": "2025-06-20",
 "runDays": 495, "publisherPlatforms": ["FACEBOOK", "INSTAGRAM"], "displayFormat": "DPA", "ctaText": "Shop now",
 "landingUrls": ["https://www.nike.com/us/en_us"], "imageUrls": ["https://scontent.../a.jpg"], "videoUrls": [],
 "sourceUrl": "https://www.facebook.com/ads/library/?id=1016451784037642", "checkedAt": "2026-10-29T04:42:29Z",
 "confidence": "high", "basis": "Read from the public Meta Ad Library page of this ad."}
```

```json
{"rowType": "advertiser", "pageName": "Nike", "activeAdsReported": 73, "adsCollected": 30, "newAdsLast30Days": 29,
 "runsOnGoogleToo": true, "googleAdsFound": 20, "verdict": "scaling",
 "verdictBasis": "29 of 30 collected ads started in the last 30 days.", "confidence": "high"}
```

```json
{"rowType": "creative-analysis", "pageName": "Gymshark", "adArchiveId": "1749316556368411", "adArchiveIds": ["1749316556368411"],
 "hookType": "social-proof", "offer": "Free delivery on orders over $75",
 "targetAudience": "Women who want gym and workout clothing and are inspired by Megan Thee Stallion's fitness lifestyle.",
 "angle": "Celebrity athlete endorsement paired with the idea that hot girl confidence comes from hard work at the gym.",
 "emotion": "pride", "claims": ["Megan Thee Stallion does gym and has the receipts to prove it", "Free delivery on orders over $75"],
 "language": "en", "inputSources": ["adText", "headline", "linkDescription", "cta", "landing"], "model": "claude-haiku-5-5",
 "sourceUrl": "https://www.facebook.com/ads/library/?id=1749316556368411", "checkedAt": "2026-10-29T06:05:04Z", "confidence": "medium",
 "basis": "Read by an AI model (claude-haiku-5-5) from: adText, headline, linkDescription, cta, landing."}
```

The creative analysis is a model's reading of the ad's own text, not a fact about the advertiser: `confidence` is `medium` and `basis` lists what was read. If the model is unavailable the layer adds nothing (a `creative-ai-unavailable` notice explains why) and nothing is charged for it.

### Notes

- Unofficial tool, not affiliated with Meta Platforms or Google. It reads the public, logged-out Ad Library, the public Google Ads Transparency Center and the advertisers' public landing pages.
- You are responsible for a lawful purpose, for complying with the terms of those services and with the rights in the advertisers' pages and creatives, and for how you use the output.
- A run that was restarted by the platform does not charge any row twice and does not write any row twice.
- Two runs that start at the same time with the same input each deliver and each pay for their own rows.
- Memory: the default layers (landing pages, Google ads, image text, creative analysis) peaked at about 270 MB and 100 ads with the video layer at about 920 MB in our measurements, so the default run needs 2048 MB (the manifest default); choose 4096 MB for several advertisers with video transcripts at once. Pictures larger than 12 megapixels are not read for text (no row, no charge).

# Actor input Schema

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

One per line. Each value is detected automatically: a Meta Ad Library URL (an advertiser view or a keyword search), a Facebook page URL (facebook.com/nike), a numeric page ID, or a search term (every advertiser whose ads match it). Free plan: the first entry only. You are responsible for a lawful purpose and for complying with Meta's and Google's terms and with the rights in the advertisers' pages and creatives.

## `maxAdsPerTarget` (type: `integer`):

Upper limit of ad rows for each entry (1-5000, default 200). Free plan: 20 ads per run at $3.75 per 1,000 ads, the rest is counted as locked; paid plans pay $2.50 per 1,000 ads (33% cheaper per row).

## `enrich` (type: `array`):

Rows added on top of the ad rows; each is charged under its own event. Landing pages: every distinct landing URL (status, title, product and price). Google ads: the same advertiser's ads in the Google Ads Transparency Center. Image text: text printed on image ads. Video transcripts: speech in video ads (slower, off by default). AI creative analysis: one row per distinct creative with hook type, offer, target audience, angle, emotion and claims, plus top hooks on the advertiser row. Free plan: one sample row per layer.

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

Two-letter country codes where the ads were delivered (US, GB, DE...), or ALL. Up to 10. A country in an Ad Library URL overrides this list for that URL.

## `adStatus` (type: `string`):

Which ads to collect. A status in an Ad Library URL overrides this for that URL.

## `maxTranscripts` (type: `integer`):

Used when Video ad transcripts is switched on, and by the free plan's sample row (0-200, default 10). Transcribing runs on CPU, so this keeps the run time bounded.

## `adsAfter` (type: `string`):

YYYY-MM-DD. Paid plans only; ignored on the free plan.

## `adsBefore` (type: `string`):

YYYY-MM-DD. Paid plans only; ignored on the free plan.

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

Skips ads already delivered in an earlier run with the same list of entries, so a weekly run pays for new ads only. Paid plans only.

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

Meta rate-limits data-center networks; the run starts on its own network and switches to this proxy when it is blocked. Residential is recommended.

## Actor input object example

```json
{
  "pageUrls": [
    "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&view_all_page_id=15087023444&search_type=page&media_type=all"
  ],
  "maxAdsPerTarget": 30,
  "enrich": [
    "landingPages",
    "googleAds",
    "imageText",
    "creativeAi"
  ],
  "countries": [
    "US"
  ],
  "adStatus": "active",
  "maxTranscripts": 10,
  "adsAfter": "",
  "adsBefore": "",
  "onlyNewSinceLastRun": false,
  "proxyConfiguration": {
    "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 = {
    "pageUrls": [
        "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&view_all_page_id=15087023444&search_type=page&media_type=all"
    ],
    "maxAdsPerTarget": 30,
    "enrich": [
        "landingPages",
        "googleAds",
        "imageText",
        "creativeAi"
    ],
    "countries": [
        "US"
    ],
    "adStatus": "active",
    "maxTranscripts": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ntriqpro/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 = {
    "pageUrls": ["https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&view_all_page_id=15087023444&search_type=page&media_type=all"],
    "maxAdsPerTarget": 30,
    "enrich": [
        "landingPages",
        "googleAds",
        "imageText",
        "creativeAi",
    ],
    "countries": ["US"],
    "adStatus": "active",
    "maxTranscripts": 10,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("ntriqpro/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 '{
  "pageUrls": [
    "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&view_all_page_id=15087023444&search_type=page&media_type=all"
  ],
  "maxAdsPerTarget": 30,
  "enrich": [
    "landingPages",
    "googleAds",
    "imageText",
    "creativeAi"
  ],
  "countries": [
    "US"
  ],
  "adStatus": "active",
  "maxTranscripts": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call ntriqpro/facebook-ads-library-scraper --silent --output-dataset

```

## MCP server setup

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