Facebook Ads Library Scraper v2 avatar

Facebook Ads Library Scraper v2

Pricing

$7.50 / 1,000 ads

Go to Apify Store
Facebook Ads Library Scraper v2

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

Arnas

Maintained by Community

Actor stats

0

Bookmarked

26

Total users

5

Monthly active users

2 days ago

Last modified

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

FieldTypeDefaultWhat it does
querystring[] (required)—Keywords (crochet), page handles (@ZapierApp), page URLs, or full Ad Library URLs. Mix freely. Page URLs / @handles return only that page's ads.
countrystringALLTwo-letter ISO country code (US, GB, DE, …) or ALL.
activeStatusenumactiveall · active · inactive.
adTypeenumallall · political_and_issue_ads.
mediaTypeenumallall · image · video · meme · image_and_meme · none.
periodenumallall · last24h · last7d · last14d · last30d.
sortByenumimpressions_descimpressions_desc · most_recent.
maxAdsinteger100Total cap across all searches. Empty for no cap.
maxAdsPerQueryintegerunlimitedCap per item in query.
scrapeAdDetailsbooleanfalseFetch extra ad details (e.g. EU reach). Slower and more expensive.
runTagstring—Stamped onto every output row's runTag field.
proxyproxyApify 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 into query
  • count → maxAds
  • limitPerSource → maxAdsPerQuery
  • scrapePageAds.countryCode → country
  • scrapePageAds.activeStatus → activeStatus
  • scrapePageAds.period → period
  • scrapePageAds.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 ad
  • position — index within the run (1-based)
  • query — which input item produced the row
  • runTag — copy of the input runTag

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.