Facebook Ads Library Scraper v2
Pricing
$7.50 / 1,000 ads
Facebook Ads Library Scraper v2
Search Meta's Ad Library by keyword, page handle, page URL, or full Ad Library URL. Pay-per-result.
Pricing
$7.50 / 1,000 ads
Rating
0.0
(0)
Developer
Arnas
Maintained by CommunityActor stats
0
Bookmarked
26
Total users
5
Monthly active users
2 days ago
Last modified
Categories
Share
Facebook Ads Library Scraper
Search Meta's Ad Library and pull every matching ad. Pass a keyword, a Facebook page handle, a page URL, or a full Ad Library URL — they all work.
Quick start
The minimum viable input is a single field:
{"query": ["crochet"]}
Or mix searches in a single run:
{"query": ["crochet", "@ZapierApp", "https://www.facebook.com/Nike"],"country": "US","activeStatus": "active","maxAds": 500}
Input
| Field | Type | Default | What it does |
|---|---|---|---|
query | string[] (required) | — | Keywords (crochet), page handles (@ZapierApp), page URLs, or full Ad Library URLs. Mix freely. Page URLs / @handles return only that page's ads. |
country | string | ALL | Two-letter ISO country code (US, GB, DE, …) or ALL. |
activeStatus | enum | active | all · active · inactive. |
adType | enum | all | all · political_and_issue_ads. |
mediaType | enum | all | all · image · video · meme · image_and_meme · none. |
period | enum | all | all · last24h · last7d · last14d · last30d. |
sortBy | enum | impressions_desc | impressions_desc · most_recent. |
maxAds | integer | 100 | Total cap across all searches. Empty for no cap. |
maxAdsPerQuery | integer | unlimited | Cap per item in query. |
scrapeAdDetails | boolean | false | Fetch extra ad details (e.g. EU reach). Slower and more expensive. |
runTag | string | — | Stamped onto every output row's runTag field. |
proxy | proxy | Apify Proxy (residential, US) | Proxy configuration. Residential proxies are required — see below. |
Page URLs and handles → the page's own ads
A Facebook page URL (https://www.facebook.com/weareallbirds, facebook.com/NotionHQ, profile.php?id=…) or an @handle (@ZapierApp) returns only the ads run by that page — the same list you get by clicking the advertiser in the Ad Library.
How it works: the actor fetches the public page over the residential proxy, reads the page's numeric Ad Library ID (for example 778794852137593 for Allbirds — note this is not the 100… profile ID in fb://profile/…), and opens …/ads/library/?view_all_page_id=<id>&search_type=page. Every row therefore has page_id equal to the resolved ID, and the resolved ID is written to the run log (Resolved page "…" → page_id=…).
- A bare word without
@(e.g.Allbirds) is still a keyword search, which also returns other advertisers that mention it. - If you already know the page ID, pass the full Ad Library URL (
https://www.facebook.com/ads/library/?view_all_page_id=<id>&search_type=page&…) — it is used as-is and skips the lookup. - If the page cannot be resolved (e.g. Meta served a login wall to every IP we tried), the actor logs a warning and falls back to a keyword search on the handle.
Proxies: residential is required
Meta blocks datacenter IPs on the Ad Library. On a datacenter proxy the Ad Library page never issues its backend GraphQL calls, so the run rotates through IPs hitting "Meta rate-limit" and ends with no ads. This actor therefore defaults to Apify Proxy residential IPs in the US — just leave the proxy field as-is and it works.
If you override the proxy, keep RESIDENTIAL in the groups. Running your own datacenter proxies, or no proxy at all, will almost certainly return nothing.
Legacy fields (still accepted)
For drop-in compatibility with the original curious_coder/facebook-ads-library-scraper input, these older field names are also accepted:
urls(array of URL objects) → folded intoquerycount→maxAdslimitPerSource→maxAdsPerQueryscrapePageAds.countryCode→countryscrapePageAds.activeStatus→activeStatusscrapePageAds.period→periodscrapePageAds.sortBy→sortBy
Output
Each ad is pushed to the run's default dataset with the upstream Meta field names preserved (ad_archive_id, page_name, is_active, start_date_formatted, publisher_platform, snapshot, spend, reach_estimate, advertiser, insights, aaa_info, …) plus three convenience fields:
ad_library_url— direct link to the adposition— index within the run (1-based)query— which input item produced the rowrunTag— copy of the inputrunTag
Pagination
maxAdsPerQuery reflects what the actor will actually return. As of v0.2.0, pagination is driven by Meta's own AdLibrarySearchPaginationQuery over HTTP: the actor bootstraps a session in Playwright, harvests the live doc_id / lsd / fb_dtsg tokens, then walks the GraphQL cursor connection until the connection ends or the cap is reached. High-volume advertisers (Duolingo, Spotify, Notion, etc.) return hundreds of ads spanning the full history that Meta exposes anonymously. Earlier versions capped at ~30.
When the run is stopped by maxAdsPerQuery (or maxAds) before the connection naturally ends, the final row in the dataset carries a nextPageCursor field — an opaque resume token. The cursor is not surfaced when pagination ran to completion (because there is nothing left to resume).
Pricing
Pay per event:
- Event key:
apify-default-dataset-item - Event title:
ad - Event description:
Single ad in the default dataset. - Event price:
$0.00075
Displays as $0.75 / 1,000 ads.