Facebook Ads Library Scraper - Meta (Facebook) Ad Library
Pricing
from $9.00 / 1,000 results
Facebook Ads Library Scraper - Meta (Facebook) Ad Library
Extract Facebook & Instagram ads from the Meta Ad Library: ad copy, image and video URLs, CTA links and start dates. Search up to 5 brands or keywords per run, or pin an exact Page ID. Re-run on a schedule and every ad is labelled new, ongoing or ended. No login.
Pricing
from $9.00 / 1,000 results
Rating
5.0
(1)
Developer
jy-labs
Maintained by CommunityActor stats
3
Bookmarked
414
Total users
51
Monthly active users
3 days ago
Last modified
Categories
Share
Facebook Ads Library Scraper
Pull Facebook and Instagram ads out of the Meta Ad Library for up to 5 brands or keywords per run. Every ad comes back labelled new, ongoing, or ended against your last run, and you don't need a login.
Input · Output · Pricing · FAQ
What you get
- Change labels across runs. Re-run the same search on a schedule and each ad is marked
new,ongoing, orended, withfirstSeenDate,lastSeenDateandrunsSeen. You see what changed instead of the same list again. SetonlyNewAdsand a run delivers only the ads it hasn't seen before. - One result per advertiser. Set
dedupeBy: "advertiser"and Max Results counts distinct accounts, not ads: 200 results means 200 different advertisers, each with anadvertiserAdCount. - Page ID pinning. Pair a keyword with an advertiser's numeric Facebook Page ID and the search only returns ads from that page.
- Match evidence on every row.
matchedByshows whether your keyword actually appears in the advertiser name, ad copy or CTA link, or whether Meta only ranked the ad for your query. - No login. The Actor doesn't use a Facebook account, cookies or a Meta developer token.
- Up to 5 keywords per run. They run one after another. Export to JSON, CSV or Excel, or read the results over the Apify API.
Output
Three real rows from a Nike search in the US on 2026-09-29, trimmed to the columns most people read first (body and links shortened):
| brand | body | startDate | ctaLink |
|---|---|---|---|
| Nordstrom Rack | Buy online and pick up in store for free! Get up to 70% off Nike, Vince… | 2026-08-03 | https://fb.com/canvas_doc/1072291375736811 |
| Foot Locker | Refresh your wardrobe with new styles from Nike, New Balance, adidas… | 2026-07-22 | https://www.footlocker.com/product/~/00051791… |
| Nike | Entra a Nike.com y encuentra actualizaciones semanales de producto con envío… | 2023-08-15 | https://www.nike.com/mx/t/calzado-de-golf-… |
Each row also includes libraryID, keyword, pageId, brandImg, isActive, platforms, images, videos, scrapeDate, matchedBy and matchEvidence. With change tracking on (the default), rows also include the change labels. The full field list:
| Field | Type | Description |
|---|---|---|
libraryID | string | Unique Meta Ad Library identifier |
keyword | string|null | The keyword you searched; null on ended-ad rows |
pageId | string|null | Page ID used for this search; null if none |
brand | string | Advertiser name |
brandImg | string | Advertiser profile image URL |
body | string | Ad copy |
startDate | string | When the ad started running (YYYY-MM-DD) |
isActive | boolean | Whether the ad is still running |
platforms | array | Where the ad runs: any of Facebook, Instagram, Audience Network, Messenger, WhatsApp, Threads. An "Unknown" entry means an icon could not be identified, so the list may be incomplete |
images | array | Image URLs (carousels included) |
videos | array | Video URLs with poster images |
ctaLink | string | Call-to-action destination URL |
matchedBy | string | page_id, visible_text, visible_partial or meta_search (see Match evidence) |
matchEvidence | object | Which extracted fields and terms matched |
advertiserAdCount | integer | Ads this advertiser was running among the ads scanned; only with dedupeBy: "advertiser" |
scrapeDate | string | When the row was collected (ISO 8601) |
adStatus | string | new, ongoing, or ended; only with change tracking on |
isNew | boolean | True when no earlier run of this search returned the ad |
firstSeenDate | string | When this monitoring stream first returned the ad |
lastSeenDate | string|null | The previous sighting before this run; null on a new ad |
runsSeen | integer | How many runs of this stream returned the ad, including this one |
The Console dataset has four views: Overview, Creatives, Changes and Advertisers.
Find long-running (winning) ads
Meta doesn't publish spend or results for commercial ads, but it does publish how long each ad has been running, and advertisers rarely keep paying for an ad that doesn't work.
- Run your search with
activeStatus: "active"so every row is an ad that is still live. - Sort the dataset by
startDate, oldest first. - Look closely at ads that have been active for 60 days or more (
scrapeDateminusstartDate). These are the creatives the advertiser has kept paying for.
On a scheduled search, runsSeen tells you the same thing from your own history: a high count means the creative has stayed in rotation across many of your runs.
Input
Quick start
- Click Try for free to open the Actor in Apify Console.
- Switch the input to the JSON tab, paste the input below, and replace
Nikewith the brand you track. - Click Start. A run like this usually finishes in about two minutes. Export the dataset as JSON, CSV or Excel.
{"keywords": ["Nike"],"country": "US","activeStatus": "active","maxResults": 20}
Everything else already has a working default. Residential proxy is on, multi-word keywords are matched as an exact phrase, and change tracking labels every row against your previous runs of the same search.
Input fields
The form shows the common fields first. Rarely changed settings are grouped under Advanced.
| Parameter | Type | Description | Default |
|---|---|---|---|
keywords | array | Brand names, products or topics, up to 5 per run | Required |
pageIds | array | Optional numeric Page IDs, matched by position to keywords. Leave an entry blank for keyword-only search. Non-numeric Page IDs are rejected before browser work starts. | - |
country | string | Country whose Ad Library is searched (22 countries or ALL). Also sets the residential proxy exit country. | US |
activeStatus | string | all, active, or inactive | all |
mediaType | string | all, image, meme, video, or none | all |
maxResults | integer | Results per keyword (1–200). Counts advertisers when dedupeBy is advertiser | 100 |
adType | string | all or political_and_issue_ads | all |
startDateMin | string | Meta's own date filter: only ads shown on or after this date. Ads that began earlier but were still running are included; check startDate | - |
startDateMax | string | Meta's own date filter: only ads shown on or before this date, so every ad returned started on or before it | - |
sortBy | string | relevancy_monthly_grouped (Meta's default) or total_impressions | relevancy_monthly_grouped |
searchType | string | exact_phrase (words together, in order) or unordered (any word, anywhere) | exact_phrase |
dedupeBy | string | none or advertiser (one row per account) | none |
trackChanges | boolean | Add new / ongoing labels against earlier runs. Adds fields only and never filters. | true |
onlyNewAds | boolean | Deliver only ads this search hasn't returned before | false |
includeEndedAds | boolean | Also emit a row for tracked ads that stopped running | false |
Advanced settings: relevanceMode (balanced / strict / all), monitorKey (names a separate history stream), requestHandlerTimeoutSecs (default 600, the per-keyword ceiling across navigation, readiness checks, scrolling, and extraction), proxy (Apify Proxy, RESIDENTIAL group, which you should leave as it is), blockMediaAssets (default on; skips downloading media bytes but still extracts every URL) and debugMode (saves a final-page screenshot). includeUnverifiedMetaSearchResults is deprecated but still accepted. Use relevanceMode instead.
To pin a keyword to one advertiser, search the advertiser in the Meta Ad Library, open their page, and copy the digits from view_all_page_id=… in the URL. Then line the IDs up by position:
{"keywords": ["Nike", "Adidas"],"pageIds": ["", "123456789"]}
Use cases
- Competitor monitoring. Schedule a weekly run with
onlyNewAdsand read the creatives your competitors launched since last week. - Creative research. Build a swipe file of ad copy, images and videos, starting with the ads that have run longest.
- Prospecting. Search the offer you sell against with
dedupeBy: "advertiser"and get a list of accounts running it, one row each. - Brand and client monitoring. Pin a Page ID and track every ad one advertiser runs in a given country.
- Market research. Compare what runs for the same keyword in different countries.
Pricing
$10 per 1,000 results on the Free plan, plus a $0.04 start charge per run. From October 12, 2026, Apify also bills platform usage to your account separately.
| Event | Price |
|---|---|
Result (apify-default-dataset-item) | $0.010 per Dataset item, falling to $0.009 on Silver and higher plans ($0.0095 on Bronze) |
Actor start (apify-actor-start) | $0.02 per GB of allocated memory |
| Platform usage (compute + residential proxy) | Included until October 12, 2026. From October 12, 2026, billed to your account separately at Apify's standard rates |
The default 2048 MB memory allocation produces two 1 GB Actor-start events, or $0.04 per run.
Worked examples on the Free plan:
- 5 results: $0.04 start + 5 × $0.010 = about $0.09
- 100 results: $0.04 start + 100 × $0.010 = about $1.04
From October 12, 2026, add platform usage to those figures. For scale, a 2-keyword run that returned 8 ads used about $0.03 of platform usage (measured 2026-09-29). Usage grows with the number of keywords and how far each search scrolls, and blockMediaAssets (on by default) keeps it low because media bytes are never downloaded. The run detail page in Apify Console always shows your actual charge.
What counts as a result depends on the options you set. The price per result stays the same:
| Setting | One result is | You are billed for |
|---|---|---|
| default | one ad | every ad the run delivers |
dedupeBy: "advertiser" | one advertiser | one row per account, not per creative |
onlyNewAds: true | one ad that is new to this search | the delta only; ads already reported are free |
includeEndedAds: true | also one ad that stopped running | those rows too, like any other result |
maxResults applies per keyword, so five keywords at 100 results can deliver up to 500 rows. A run that delivers no rows has no result charge, but the start charge still applies (and, from October 12, 2026, platform usage for the time the run took).
FAQ
Do I need a Facebook account, login or API token?
No. The Actor reads the public Meta Ad Library pages, so there is no Facebook login, no account cookies and no Meta developer app or access token. You still get programmatic access through Apify's REST API, webhooks, schedules and integrations such as Google Sheets, Zapier and Make.
How many keywords can I search at once?
Up to 5 per run, processed one after another. Blank entries are dropped, and a sixth non-empty keyword is rejected before the browser starts.
What do new, ongoing, and ended mean?
new: no earlier run of this search returned the ad.ongoing: an earlier run already reported it.ended: the ad was tracked and has now been missing for two consecutive runs. One absence isn't counted, becausemaxResultscaps what a run sees and Meta reorders its results.
ended rows appear only when you set includeEndedAds: true.
Why did a run return fewer rows than maxResults?
The run log says which reason applied:
- the keyword really has fewer ads;
- the per-keyword time limit ran out (raise
requestHandlerTimeoutSecs); relevanceMode: "strict"dropped ads that never show your keyword;dedupeBy: "advertiser"ran into too many repeats from the same accounts.
Does it return ad spend, reach or targeting data?
No. Meta publishes spend and impressions only for political and issue ads, and the Actor doesn't extract per-ad EU reach or targeting figures. The country input picks which country's Ad Library is searched, not the audience an ad declares.
Is this legal?
Meta Ad Library publishes advertising data for transparency. Whether a particular collection or use is allowed depends on the applicable terms, laws, jurisdiction and use case. You are responsible for reviewing Meta's terms and getting legal advice when appropriate.
Change monitoring in detail
Change tracking (trackChanges) is on by default. Each search keeps its own history in a key-value store named meta-ad-monitor inside your own Apify account, so nobody else can see it. Deleting that store resets the history. A stream is identified by the search itself (keywords, page IDs, country, ad type, status and media type), so a saved task on a schedule lines up with itself automatically, and keyword order doesn't matter. Set monitorKey if one input needs separate histories, for example one per client.
- Labels, not filters.
trackChangesadds fields and never removes rows.onlyNewAds: trueis the filter. The first run returns everything, because everything is new; after that you get only what appeared since. Ads that are filtered out are still recorded, so they are never re-reported as new. If the history can't be read, the run delivers every row rather than none, and says so in the log. - Ended ads need
includeEndedAds: true. These rows are charged like any other result. - Only complete runs update the history. A failed or partial run saw less of the Ad Library than it should have, so it is never folded in. Otherwise a broken run would retire ads that are still running.
- Overlapping runs merge their results instead of overwriting each other. Still, set the schedule interval longer than one run takes.
- The run's status message shows the change summary, for example
6 new, 106 ongoing, so you can see it in the run list without opening the run.
Prospecting for advertisers
With dedupeBy: "advertiser", maxResults counts distinct advertisers. For each advertiser the Actor keeps its best-matching ad (deduplication happens after relevance ranking). Deduplication covers the whole run, so an advertiser found under two keywords is still one row, and advertiserAdCount shows how many ads that account was running. The Actor scans further to fill your quota, up to 400 ads per keyword. On free consultation with maxResults: 200, a measured run scanned 423 ads and delivered 200 distinct advertisers.
{"keywords": ["free consultation"],"country": "US","dedupeBy": "advertiser","maxResults": 200}
Don't combine this with a Page ID. A Page ID search already covers a single advertiser, so deduplication leaves one row.
Match evidence
Meta decides which ads belong to a keyword search and sometimes returns ads whose visible text never mentions it. Every row says how it matched:
page_id: the search was pinned to a Page ID, which is the strongest evidence.visible_text: every keyword term appears in the advertiser name, ad copy or CTA URL.visible_partial: some of the terms appear.meta_search: Meta returned the ad, but the extracted fields don't show the keyword.
relevanceMode: "balanced" (the default) fills your quota in that order. strict keeps only page_id and visible_text rows; for slogan-only brands it can return very few, and the log shows a [yield-alarm] warning when that happens. all keeps Meta's order untouched. matchEvidence.phraseMatch ranks exact-phrase hits higher within a tier. visibleMatch: false means the extracted text doesn't prove a match; the keyword can still appear inside the creative image.
Empty results and troubleshooting
Some keywords really do have no ads, and a run that reports that is doing its job. A keyword with zero rows counts as a completed search when the page rendered, Meta showed its no-results text, ad data arrived, or strict relevance removed the candidates. It counts as a failure when Meta refused to serve the search (a challenge page, a verification wall, a JavaScript-disabled shell, or rate limiting), when the page never rendered and neither ad data nor no-results text arrived, or when navigation failed or timed out. The Actor rotates the page and proxy route and retries while time allows. If every keyword fails, SUMMARY.status is failed. A mix of successful and failed keywords gives completed_partial.
Scrolling that stops short of the requested result count because of time limits, rate limiting, or an interruption is also recorded explicitly. Usable rows are still delivered, with a partial keyword status, and any partial keyword makes the run completed_partial. An incomplete keyword that delivers no rows has an error status, for example error: runtime budget exhausted when its scroll ran out of time, and counts as a failed keyword toward failed / completed_partial above. These runs do not advance change history or report newly ended ads. A fulfilled result quota, ordinary pagination exhaustion, and confirmed empty searches remain successful.
To investigate a run, open its Log and search for [diagnostic] to follow each stage from start-up through navigation, scrolling, extraction and dataset writes. The run's key-value store has a DIAGNOSTICS record with the latest 50 events and the first and last failures. Diagnostic records never contain your search text, page IDs, full URLs or ad copy.
What's new
- 2026-09-29:
platformsshows where each ad runs again, after Meta changed how placements are drawn in late September 2026. An icon that cannot be identified is listed as"Unknown"next to the ones that were, so an incomplete list never looks complete. - 2026-10-12: Platform usage (compute and residential proxy) will be billed to your Apify account at standard rates instead of being included in the result price. See Pricing.
- 2026-09-15: Run diagnostics:
[diagnostic]log lines and aDIAGNOSTICSrecord in each run's key-value store. - 2026-08-31: The default sort no longer sends Meta its own sort parameters, which had switched some searches to an unrelated feed.
- 2026-08-24: Multi-word keywords are now searched as an exact phrase. Added one result per advertiser (
dedupeBy) and only-new ads (onlyNewAds). Pagination no longer stops early when an ad's text contains "no results".
Something broken? Open an Issue on this page.
Support
- Issues and feature requests: Actor issues
- Apify documentation: docs.apify.com
Legal notice
This Actor collects publicly visible data from the Meta Ad Library without accessing private accounts. You are responsible for making sure your collection and use of the data comply with Meta's terms and applicable laws.