# Facebook Ads Library Scraper (`sfoln/facebook-ads-search`)

Search the Meta Ad Library (Facebook and Instagram) by keyword, page ID or company: one row per ad with text, CTA, landing URL, images, videos, dates, platforms and, where Meta discloses them, spend and impressions. $1 per 1,000 ads + $0.004 per page.

- Family: Ad intelligence
- Categories: Social media, Lead generation, Ecommerce
- Availability: on request (private on Apify). Email contact@sfoln.com with subject "Access request: Facebook Ads Library Scraper (sfoln/facebook-ads-search)" before calling; calls fail until it is public.
- JSON: https://www.sfoln.com/actors/facebook-ads-search.json
- MCP: https://mcp.apify.com?tools=sfoln/facebook-ads-search
- REST (sync): POST https://api.apify.com/v2/actors/sfoln~facebook-ads-search/run-sync-get-dataset-items
- REST (async): POST https://api.apify.com/v2/actors/sfoln~facebook-ads-search/runs

Facebook Ads Library Scraper searches the Meta Ad Library (Facebook, Instagram, Messenger, Audience Network) by keyword, Facebook page ID or company name and returns one clean dataset record per ad: ad archive ID, advertiser page, start/end dates, active status, platforms, ad text, headline, call to action, landing URL, media type, image and video URLs and, where Meta discloses it, impressions, spend and targeted countries. Filter by country, active status, media type, political/issue ads, language and date range. Built for competitor research, creative inspiration, ad monitoring, agencies and AI agents.

## Price per delivered record

| Event | Price | Per 1,000 | Charged for |
| --- | --- | --- | --- |
| Facebook ad (`facebook-ad`) | $0.001 | $1 / 1,000 | Charged once per ad record delivered from the Meta Ad Library (recordType ad). Duplicates, query summary rows and failed requests are not charged. |
| Ad Library page (`facebook-ads-query`) | $0.004 | $4 / 1,000 | Charged once per Ad Library results page fetched for a query (a page holds up to ~30 ads). A page without new ads is charged only when the upstream provider billed it. Failed requests are not charged. |

Pay-per-event, USD, billed by Apify; no platform usage charge. Only records with status `ok` are charged. Cap a run with `maxTotalChargeUsd`. Apify free plan: up to 10 per run.

## Run

```bash
curl -X POST "https://api.apify.com/v2/actors/sfoln~facebook-ads-search/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries":["running shoes"],"maxAdsPerQuery":10,"country":"US"}'
```

MCP client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=sfoln/facebook-ads-search"
    }
  }
}
```

Example prompt: Find 20 active Facebook and Instagram ads in the US that mention "running shoes" and summarize their headlines, calls to action and landing pages.

## Input

Search the Meta Ad Library by keyword, Facebook page ID or company name. Each query returns one dataset record per ad plus one summary record.

| Field | Type | Default | Meaning |
| --- | --- | --- | --- |
| `queries` | array | — | Search keywords: Keywords to search the Ad Library for (ad text match), one per line. Accounts on the Apify free plan can process up to 10 queries per run (keywords, page IDs and company names together). |
| `pageIds` | array | — | Facebook page IDs: Numeric Facebook page IDs, or Ad Library URLs containing view_all_page_id=…, to list all ads of that page. |
| `companyNames` | array | — | Company names: Advertiser / company names; the upstream resolves the name to its Ad Library page (a page ID is more precise). |
| `maxAdsPerQuery` | integer | `50` | Max ads per query: Maximum ads returned per keyword, page or company (1–500). Ads are fetched in pages of up to ~30. |
| `country` | string | `"ALL"` | Country: 2-letter country code where the ads were delivered (e.g. US, GB, DE), or ALL. |
| `status` | string | `"ACTIVE"` | Ad status: Only active ads, only inactive ads, or both. One of `"ACTIVE"`, `"INACTIVE"`, `"ALL"`. |
| `mediaType` | string | `"ALL"` | Media type: Filter by creative type. MEME means image + text. One of `"ALL"`, `"IMAGE"`, `"VIDEO"`, `"MEME"`, `"IMAGE_AND_MEME"`, `"NONE"`. |
| `adType` | string | `"all"` | Ad category (keyword search only): All ads, or only political and social-issue ads. One of `"all"`, `"political_and_issue_ads"`. |
| `searchType` | string | `"keyword_unordered"` | Keyword matching (keyword search only): Match any of the words, or the exact phrase. One of `"keyword_unordered"`, `"keyword_exact_phrase"`. |
| `sortBy` | string | `"total_impressions"` | Sort by: Most impressions first, or most recent first. One of `"total_impressions"`, `"relevancy_monthly_grouped"`. |
| `language` | string | — | Language: Optional 2-letter language code of the ad (EN, ES, FR…). |
| `startDate` | string | — | Shown from (YYYY-MM-DD): Optional: only ads with impressions on or after this date. |
| `endDate` | string | — | Shown until (YYYY-MM-DD): Optional: only ads with impressions on or before this date. |
| `maxQueries` | integer | `100` | Max queries: Safety cap on keywords + pages + companies processed in this run. |
| `concurrency` | integer | `4` | Concurrency: Queries processed in parallel (1–8). |
| `itemTimeoutSecs` | integer | `600` | Time limit per query (seconds): Pagination for one keyword, page or company stops cleanly shortly before this limit (60–3600). Raise it for very large per-query limits. |
| `includeRaw` | boolean | `false` | Include raw upstream response: Attach the unmodified upstream ad object to each ad record under `raw` (larger output). |

Example input:

```json
{
  "queries": [
    "running shoes"
  ],
  "maxAdsPerQuery": 10,
  "country": "US"
}
```

## Output

One record per input item with `status` (`ok` is charged; `not_found`, `error`, `skipped_*` are free) and `charged`. The run stores an `OUTPUT` summary record.

| Field | Type | Meaning |
| --- | --- | --- |
| `input` | string | object | Input: The input query this record belongs to. |
| `recordType` | string | Row type: ad (one per ad, charged facebook-ad) \| query (one summary per query, free). |
| `status` | string | Status: ok \| not_found \| error \| skipped_invalid \| skipped_budget \| skipped_free_plan |
| `charged` | boolean | Charged: Whether this record incurred a pay-per-event charge. |
| `chargedEvent` | string | Charged event: Pay-per-event event charged for this record. |
| `source` | string | Source: Upstream data source (scrapecreators = ScrapeCreators API over the public ad library). |
| `fetchedAt` | string | Fetched at: ISO timestamp. |
| `error` | object | Error: code / message when status is not ok. |
| `warnings` | array | Warnings: Non-fatal notes (e.g. stopped early). |
| `query` | string | null | Query: Keyword, page ID or company name the row belongs to. |
| `queryType` | string | null | Query type: keyword \| page \| company. |
| `position` | integer | null | Position: 1-based position of the ad within the query results. |
| `adArchiveId` | string | null | Ad archive ID: Meta Ad Library ID of the ad. |
| `adLibraryUrl` | string | null | Ad Library URL: Public Ad Library link to the ad (snapshot). |
| `pageId` | string | null | Page ID: Advertiser's Facebook page ID. |
| `pageName` | string | null | Page name: Advertiser's page name. |
| `pageUrl` | string | null | Page URL: Advertiser's Facebook page. |
| `pageLikeCount` | integer | null | Page likes: Page like count at fetch time. |
| `pageCategories` | array | Page categories: Page categories. |
| `isActive` | boolean | null | Active: Ad is currently running. |
| `startDate` | string | null | Start date: ISO date the ad started running. |
| `endDate` | string | null | End date: ISO date the ad stopped (or last seen) running. |
| `totalActiveTimeSecs` | integer | null | Active time (s): Total active time in seconds when reported. |
| `platforms` | array | Platforms: Publisher platforms: facebook, instagram, audience_network, messenger, threads. |
| `adText` | string | null | Ad text: Primary text (body) of the ad; first card's body for multi-version ads. |
| `headline` | string | null | Headline: Link title / headline. |
| `linkDescription` | string | null | Link description: Text under the headline. |
| `linkUrl` | string | null | Landing URL: Destination link. |
| `displayUrl` | string | null | Display URL: Domain shown on the ad (caption). |
| `ctaText` | string | null | CTA text: Call-to-action button text. |
| `ctaType` | string | null | CTA type: Call-to-action code, e.g. SHOP_NOW, LEARN_MORE. |
| `mediaType` | string | null | Media type: image \| video \| multi_images \| carousel \| dco \| dpa \| text … |
| `imageUrls` | array | Image URLs: Creative images (original resolution where available). |
| `videoUrls` | array | Video URLs: Creative videos (HD where available). |
| `thumbnailUrl` | string | null | Thumbnail: Video preview image or resized first image. |
| `cardCount` | integer | null | Cards: Number of carousel / version cards. |
| `collationCount` | integer | null | Versions: Number of ad versions grouped under this ad. |
| `languages` | array | Languages: Ad languages when the library reports them. |
| `impressionsText` | string | null | Impressions: Impressions range text when Meta discloses it (political / EU ads). |
| `reachEstimate` | integer | null | Reach estimate: Estimated reach when disclosed. |
| `spendLower` | number | null | Spend (lower): Lower spend bound when disclosed (political ads). |
| `spendUpper` | number | null | Spend (upper): Upper spend bound when disclosed. |
| `currency` | string | null | Currency: Currency of the spend bounds. |
| `targetedCountries` | array | Targeted countries: Targeted / reached or political countries when reported. |
| `targetsEu` | boolean | null | Targets EU: EU transparency data present (ad details only). |
| `euTotalReach` | integer | null | EU reach: Total EU reach (ad details only). |
| `audienceAgeMin` | integer | null | Audience age min: Targeted minimum age (ad details only). |
| `audienceAgeMax` | integer | null | Audience age max: Targeted maximum age (ad details only). |
| `audienceGender` | string | null | Audience gender: Targeted gender (ad details only). |
| `audienceLocations` | array | Audience locations: Targeted locations (ad details only). |
| `payers` | array | Payers: Who paid for the ad (EU transparency; ad details only). |
| `beneficiaries` | array | Beneficiaries: Who benefits from the ad (EU transparency; ad details only). |
| `reachBreakdown` | array | Reach breakdown: EU reach by country / age range / gender (ad details only). |
| `adsDelivered` | integer | null | Ads delivered: Ads delivered for this query (summary rows). |
| `pagesFetched` | integer | null | Pages fetched: Upstream pages fetched (summary rows). |
| `queryFeesCharged` | integer | null | Page fees charged: facebook-ads-query events charged for this query (summary rows). |
| `totalResults` | integer | null | Total results: Total matching ads reported by the library (summary rows; capped at 50,001 by Meta). |
| `stopReason` | string | null | Stop reason: limit \| end \| budget \| max_pages \| deadline \| error \| empty_pages (summary rows). |

Example record:

```json
{
  "input": {
    "kind": "page",
    "value": "15087023444"
  },
  "recordType": "ad",
  "query": "15087023444",
  "queryType": "page",
  "position": 1,
  "adArchiveId": "1212560900568826",
  "adLibraryUrl": "https://www.facebook.com/ads/library?id=1212560900568826",
  "pageId": "15087023444",
  "pageName": "Nike",
  "pageUrl": "https://facebook.com/nike",
  "pageLikeCount": 37497718,
  "pageCategories": [
    "Ropa deportiva"
  ],
  "isActive": true,
  "startDate": "2025-06-17T07:00:00.000Z",
  "endDate": "2025-06-18T07:00:00.000Z",
  "platforms": [
    "facebook"
  ],
  "adText": "Que el frío no te detenga. Explora la colección de invierno con estilo y actitud Nike. 🧥",
  "headline": "Look de invierno activado",
  "linkUrl": "https://fb.com/canvas_doc/569658969305127",
  "displayUrl": "fb.com",
  "ctaText": "Learn more",
  "ctaType": "LEARN_MORE",
  "mediaType": "video",
  "imageUrls": [],
  "videoUrls": [
    "https://video.xx.fbcdn.net/…hd.mp4"
  ],
  "thumbnailUrl": "https://scontent.xx.fbcdn.net/…preview.jpg",
  "impressionsText": null,
  "spendLower": null,
  "spendUpper": null,
  "targetedCountries": [],
  "status": "ok",
  "charged": true,
  "chargedEvent": "facebook-ad",
  "source": "scrapecreators",
  "fetchedAt": "2026-10-14T10:00:00.000Z"
}
```

## Related

- [Ad Library Scraper – Meta, Google & TikTok](https://www.sfoln.com/actors/ad-library-scraper.md) (`sfoln/ad-library-scraper`)
- [Facebook Ad Details Scraper (by Ad ID)](https://www.sfoln.com/actors/facebook-ad-lookup.md) (`sfoln/facebook-ad-lookup`)
- [Google Ads Transparency Scraper](https://www.sfoln.com/actors/google-ads-transparency.md) (`sfoln/google-ads-transparency`)
- [LinkedIn Ads Library Scraper](https://www.sfoln.com/actors/linkedin-ads-search.md) (`sfoln/linkedin-ads-search`)
- [TikTok Ads Library Scraper](https://www.sfoln.com/actors/tiktok-ads-search.md) (`sfoln/tiktok-ads-search`)

Publisher: SFOLN LLC, contact@sfoln.com. Catalogue: https://www.sfoln.com/catalog.json. Agent guide: https://www.sfoln.com/agents.md.
