Facebook Ads Library Scraper - Meta Ad Library API + Creatives
Pricing
from $1.20 / 1,000 ads
Facebook Ads Library Scraper - Meta Ad Library API + Creatives
Scrape the Facebook Ads Library (Meta Ad Library) by keyword, advertiser or pasted URL for every ad creative, including the dynamic and carousel variants others drop. Filters are enforced and reported, result caps are exact, and failed or filtered rows are free.
Pricing
from $1.20 / 1,000 ads
Rating
0.0
(0)
Developer
Blackcube Agency AB
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
32 minutes ago
Last modified
Categories
Share
Facebook Ads Library Scraper — Meta Ad Library API + Creatives
More from this account: YouTube Transcript Suite · Website Contact & Email Suite · Career Site & ATS Jobs Suite · Google News Suite · Keyword Research Suite · Shopify Store Intelligence Suite · eBay Data Suite · Amazon Reviews Suite · Reddit · Vinted
You are charged for one thing: an ad that matched what you asked for and came back with something you can use. Filtered ads, ads Meta has withheld, empty results, bad inputs and failed requests are all free rows that tell you why. There is no start fee, so a run that returns nothing costs nothing.
Search the Facebook Ads Library and Meta Ad Library by keyword, by advertiser, or by pasting a URL straight from your browser. Get the ad copy, the headline, the call to action, the destination link, the advertiser, how long the ad has been running — and the actual image and video files.
Why ads come back empty from other tools
About 42% of the ads in the Ad Library are dynamic — the creative rotates across several variants instead of being one fixed image or video. Tools that read only the ad's main creative slot find nothing on those, so they hand you a row with no picture, no video, and a headline like {{product.name}}.
Measured on a single 500-ad run of this Actor, on live data:
| Share of the 500 ads | |
|---|---|
| Ads that returned at least one image or video | 100% |
| Same ads, counting only the main creative slot | 58.2% |
| Ads that were dynamic (multi-variant) | 41.8% |
| Ads that returned real ad copy | 98.8% |
| Ads that returned a destination link | 98.8% |
Every variant comes back as its own entry with its own media, copy, headline and link, and the row still counts as one ad on your bill.
Meta also ships unfilled template slots — {{product.name}}, {{product.brand}} — as if they were real ad text. Those are removed rather than passed through, and the row is flagged so a pipeline can tell "the advertiser wrote no headline" apart from "Meta didn't fill this one in".
What you get for every ad
| Creative | ad copy, headline, caption, call-to-action text and type, destination link |
| Media | every image and video, highest quality available, unwatermarked where Meta offers both, plus video poster frames |
| Variants | each dynamic-creative variant with its own copy, headline, link and media |
| Timing | start date, whether it is still running, and daysRunning as a number you can sort on |
| Scale signal | how many near-identical ads Meta groups with this one |
| Advertiser | page name, page ID, page URL, profile picture, page likes, page categories |
| Distribution | which of Facebook, Instagram, Messenger, Threads, WhatsApp and Audience Network it runs on |
| Flags | AI-generated media, sensitive content, gating status, format |
Identical field names on every row, every format, every country.
About spend, reach and impressions
Meta publishes these only for political and social-issue ads. On ordinary commercial ads they do not exist — across 500 live commercial ads, the fill rate for spend, reach and impressions was 0%.
You will see other tools advertise them anyway. Here those fields are null on commercial ads and populated on political ones, because a fabricated number silently corrupts whatever you filter or model with it. If you are researching political advertising you get them; if you are researching a supplement brand, nobody has them.
Filters are enforced, and the run tells you what they removed
Every filter is applied to every ad before it can be delivered or billed, and the run reports how many ads each one removed. A filter that cannot be honoured is never silently dropped — a date you type in a shape we cannot read comes back as a row saying so, instead of quietly widening your search.
startedAfter/startedBefore— ISO datesminDaysRunning— the usual way to find proven winnersminCollationCount— only creatives the advertiser is scalingmediaType— checked against the media actually extractedpublisherPlatforms,advertiserNameContains,textContains,onlyDynamicCreative,excludeGated
Ads removed by your filters are never charged.
Caps are exact
maxAds: 500 delivers 500 ads and stops. Not 530. The run report states how many ads it saw, how many it delivered, and how many each filter removed, so the arithmetic always closes.
Nothing is truncated silently
Every run says why it stopped:
stopReason | What it means |
|---|---|
endOfResults | Meta had nothing more. This is a complete answer. |
capReached | Your own maxAds stopped it — more ads exist. |
pageBudgetReached | The run's page budget stopped it — more ads exist. |
sourceStopped | Meta stopped answering — some ads were not reachable. |
isComplete is true only in the first case. No other tool in this category publishes this, and it is the difference between "that is all there is" and "that is all we got".
Monitoring: pay only for what is new
Set onlyNew: true and schedule the run. Ads already delivered for that input are skipped and not charged unless something about them changed — whether it is still live, when it ended, or how many siblings Meta groups with it.
Rewritten ad copy does not count as a change. Advertisers reword constantly, and billing you for that would re-charge a whole dataset for a typo fix.
Each input keeps its own memory, so a second scheduled task over an overlapping brand list still returns everything on its first run.
How to scrape the Facebook Ads Library by keyword
Put your terms in searchTerms and pick countries — the Ad Library is country-scoped, so the country decides which ads exist at all. Use exactPhrase for a phrase rather than loose keywords.
{"searchTerms": ["protein powder", "creatine"],"countries": ["US"],"activeStatus": "active","maxAds": 500}
How to scrape a competitor's Facebook ads
Open the advertiser in the Ad Library, copy the URL from your address bar, and paste it in. The search term, country, active status and media type in that URL are used as-is — you do not have to re-enter them.
{"adLibraryUrls": ["https://www.facebook.com/ads/library/?active_status=all&country=US&view_all_page_id=590393174322587"],"maxAds": 1000}
Or give advertiserPageIds a list of numeric page IDs to track a whole competitor set in one run, with every row attributed to the advertiser it came from.
How to find winning Facebook ads
A creative still running after months is one the advertiser keeps paying for. Sort or filter on daysRunning, and use minCollationCount to keep only creatives being scaled rather than one-off tests.
{"searchTerms": ["skincare"],"countries": ["US"],"activeStatus": "active","minDaysRunning": 60,"minCollationCount": 3,"maxAds": 300}
How to scrape Instagram ads
Meta runs one library across its platforms. Filter with publisherPlatforms: ["INSTAGRAM"] to keep only ads that run on Instagram; each row also lists every platform the ad appears on.
How to download Facebook ad creatives
Each row carries direct media URLs — highest quality Meta offers, unwatermarked where there is a choice, with poster frames for video. Take the media array and fetch the URLs. Dynamic ads carry each variant's media separately, with the variant it belongs to.
How to use it as a Meta Ad Library API
Start a run and read the dataset over HTTP like any other endpoint. The official Meta Ad Library API needs identity verification and returns political and social-issue ads only; this covers commercial advertising, needs no key or approval, and returns a flat, consistent schema. Output is available as JSON, CSV or Excel.
Output
Two row types, told apart by type.
ad — the thing you asked for, and the only thing charged.
{"type": "ad","adArchiveId": "3604351659703170","adLibraryUrl": "https://www.facebook.com/ads/library/?id=3604351659703170","pageName": "Paleovalley","pageId": "590393174322587","pageLikeCount": 195792,"pageCategories": ["Food & Drink"],"title": "BOGO Bone Broth Protein","body": "If you've been waiting to try Paleovalley's bone broth protein…","ctaText": "Shop now","ctaType": "SHOP_NOW","linkUrl": "https://paleovalley.com/offers/grass-fed-bone-broth-protein-bogo-a","displayFormat": "DCO","isDynamicCreative": true,"hasUnresolvedPlaceholder": true,"mediaCount": 2,"media": [{ "kind": "video", "url": "https://…", "previewImageUrl": "https://…", "cardIndex": 0 }],"variants": [{ "index": 0, "title": "BOGO Bone Broth Protein", "body": "2 bags for $60…", "media": [] }],"startDate": "2026-07-09","endDate": null,"isActive": true,"daysRunning": 39,"collationCount": 1,"publisherPlatforms": ["FACEBOOK", "INSTAGRAM", "MESSENGER", "THREADS"],"spend": null,"currency": null,"impressions": null,"reachEstimate": null,"searchTerm": "protein powder","searchCountry": "US","scrapedAt": "2026-08-17T13:52:00.000Z"}
notice — free, and always says why: filteredOut, gatedByMeta, noResolvableCreative, noResults, invalidInput, notAttempted, requestFailed, blocked.
endDate is null while an ad is still running. Meta returns a far-future placeholder there, which is not a real end date, so isActive and daysRunning carry the meaning instead.
A full completeness and billing report is written to the key-value store as RUN_REPORT.
Pricing
From $1.00 per 1,000 ads, tiering down with your Apify plan. No start fee. No monthly minimum.
You are charged for delivered ads only. Filtered, gated, empty, failed and never-attempted rows are free, and with onlyNew a repeat run charges only for ads that are new or that changed.
Nothing is ever added to your search. If you supply Ad Library URLs or advertiser IDs, those are the only things searched. A run started with no input at all returns a small 10-ad sample so you can see the output shape, and says so in the log — it can never run up a bill on your behalf.
Input reference
Every field is documented in the Input tab. The proxy setting should be left at its default — it is the only configuration this Actor is tested on.
Notes
- Please raise anything wrong or missing on the Issues tab.
- The Ad Library is public transparency data. No login, no cookies and no account are required or accepted.
- Unofficial. This Actor is not affiliated with, endorsed by, or connected to Meta Platforms, Inc., Facebook or Instagram. All trademarks belong to their owners. Use the data in line with Meta's terms and the law that applies to you.
Run it without configuring anything — See which ads are running for a term, a ready-made example you can start as-is or copy.
Use cases
- See what a competitor is spending on. Every live creative an advertiser is running, including the variants most scrapers drop.
- Research a category before you buy media. Search by keyword to see the angles already saturating a market.
- Track a campaign over time. A scheduled run captures creatives before they are rotated out.
- Build a swipe file. Creative, copy, run dates and platform on every row.
Run it on a schedule
A one-off pull answers a question; a schedule answers it every day without you. Open Schedules in the Apify Console, point a cron at this Actor, and the dataset keeps filling on its own — no server, no cron box, no babysitting. Everything here is built to be re-run: you are billed per ad delivered, so a scheduled run that finds nothing new costs nothing.
FAQ
Do I need a Meta or Facebook account?
No. The Ad Library is public and this reads it directly.
Are carousel and dynamic creatives included?
Yes. Those variants are the ones most scrapers silently drop, and they are often the best-performing ones.
Can I search by advertiser instead of keyword?
Yes — keyword, advertiser or a pasted Ad Library URL.
Which countries can I filter to?
Any country the Ad Library covers, selected per run.
Something wrong, or a field you need that is missing? Open an issue on the Issues tab — it is read and it gets fixed. If this saved you time, a rating on the Store page helps the next person find it.