Facebook Ad Library Scraper — Facebook Ads by Keyword & Country
Pricing
from $2.00 / 1,000 ads
Facebook Ad Library Scraper — Facebook Ads by Keyword & Country
Facebook ads by keyword, advertiser page or country, from the Ad Library: advertiser, page ID, flight dates, live status, platforms, creative text, landing page, media URLs and EU spend bands. From $2.00 per 1,000 ads; transcripts are an opt-in add-on. A search that finds nothing is never charged.
Pricing
from $2.00 / 1,000 ads
Rating
0.0
(0)
Developer
Steadyfetch Team
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Type a keyword, an advertiser's name or paste an Ad Library link and get their Facebook and Instagram ads back as structured rows. That link can be a single ad's own link (…/ads/library/?id=123…), a bare ad ID, or an advertiser's page link; a single ad is a first-class input here, not a workaround. One JSON row per ad: the advertiser and page ID, when the ad started and stopped, whether it is still running, the platforms it runs on, the ad's headline, caption and body copy, its landing page, its video or image URL, the collation it belongs to, and the EU spend and impressions bands where Meta publishes them. From $2.00 per 1,000 ads on the Business plan ($4.00 on the free plan), platform usage included, no start fee. You are charged only when an ad row lands in your dataset: a search that matches nothing, a walled or rate-limited fetch and an ad whose row cannot be read all cost $0.
Using an AI agent? Pin this actor in Apify's MCP server with one link: https://mcp.apify.com?tools=steadyfetch/facebook-ad-library-scraper
- Actor id:
steadyfetch/facebook-ad-library-scraper - Input:
{ "searchQueries": ["fitness app"] }— the one field you have to set. - Cap the bill: set
maxTotalChargeUsdon the run (a run option, not Actor input), e.g.0.50— the run stops when it reaches it. - Your cap is the cap.
maxAds(default 100) caps the whole run andsearchMaxAds(default 25) caps each keyword or page — the run never delivers or bills a row past either. If your input carriesmaxItems,resultsLimit,limitorcountinstead — the names other Ad Library scrapers use — the smallest of them is read asmaxAdsand one uncharged note row says so. AddmaxTotalChargeUsdand the run stops at whichever comes first; rows already in hand ship, uncharged if they could not be billed.
Just want to see it work? Click Start with nothing set and the run is a 3-ad sample — currently running US ads matching "fitness app", charged like any run (about $0.012 on the free plan, $0.006 on Business). Set only the settings — a country, an ad format, a cap — and no keyword or link, and that same sample runs under your settings, with one uncharged note row saying which ones it used.
Want the ad's words too? Turn on Add the ad's transcript (includeTranscript) and every ad with a video creative is also transcribed — transcript, the first-3-seconds hook3s, language, durationSeconds and timestamped segments ride the same row. That is charged as one extra Ad transcript, and only when a transcript is actually delivered. If transcripts are the whole reason you are here, our Facebook Ads Transcript Scraper is built around them and also reads image-ad text and on-screen text on silent ads.
What you get
| Field | What it is |
|---|---|
adArchiveId | The ad's Ad Library ID — the one stable key. |
adLibraryUrl | A link straight back to the ad in Meta's Ad Library. |
pageName · pageId · pageProfileUri | The advertiser: their page name, its numeric ID and their profile link. |
pageCategories · pageLikeCount · pageIsDeleted · byline | How Meta files the advertiser, their follower count, and the disclaimer byline on political ads. |
isActive · startDate · endDate · totalActiveTimeSeconds | The flight: whether it is still running, and when it ran. |
publisherPlatforms · countries | Where the ad runs — Facebook, Instagram, Messenger, Audience Network, Threads — and the countries Meta names for it. |
displayFormat · videoUrl · imageUrl | The creative: its format, and a direct link to the video or image. |
title · caption · linkDescription · linkUrl | The ad's headline, its display URL and the page it sends people to. |
adText · adTextIsTemplate | The ad's body copy — and a flag that is true when Meta serves a dynamic-product placeholder ({{product.name}}) instead of words, so you can filter template ads out instead of reading them as copy. |
ctaText · ctaType | The call-to-action button. |
categories · gatedType · containsSensitiveContent · containsDigitalCreatedMedia · disclaimerLabel | Meta's own classification of the ad, including its AI-generated-media flag. |
collationId · collationCount | One creative running under several ad IDs: the group, and how many ads are in it. |
currency · spend · impressionsText · reachEstimate | The EU spend, impressions and reach bands, where the law makes Meta publish them. |
transcript · hook3s · language · durationSeconds · segments | Only with Add the ad's transcript on. |
searchQuery · sourceIndex | Which keyword, page or link this row came from, so a multi-query run sorts itself. |
status · charged · statusReason | What happened to this ad, whether it was billed, and why — on every row. |
What is null, and why. spend, impressionsText and reachEstimate are filled only where the law makes Meta publish them — EU-targeted and political ads. On an ordinary US ad they are null, and that is the Ad Library's answer, not a scrape miss. The advertiser's phone number, business address and page history live on the advertiser's About tab, not on the ad, and are not on this row. Every one of the 50 fields is present on every row: a value or null, never a column that comes and goes.
Column names are ours and they stay put. Meta's wire is read in one place and renamed once, so a Meta rename does not rename your columns, and a fixed-schema table or sheet never breaks on a new row. What a field means is in the table above, not in a Facebook internal name.
What a row looks like
One delivered row from a real run — the keyword fitness app, 2026-09-12. One ad row is one Ad charge; the transcript fields are null because this run did not turn transcripts on. The advertiser's landing page and the creative's media link are shown here as placeholders — Facebook signs the media URL and expires it within days.
{"status": "delivered","charged": true,"statusReason": null,"adArchiveId": "1507887230933843","adLibraryUrl": "https://www.facebook.com/ads/library/?id=1507887230933843","searchQuery": "fitness app","pageId": "102806245720688","pageName": "Troponin Supplements","pageProfileUri": "https://facebook.com/TroponinSupplements","pageCategories": ["Vitamins/supplements"],"pageLikeCount": 1632,"pageIsDeleted": false,"byline": null,"isActive": true,"startDate": "2026-03-20T07:00:00.000Z","endDate": "2026-09-12T07:00:00.000Z","totalActiveTimeSeconds": null,"publisherPlatforms": ["FACEBOOK","INSTAGRAM","AUDIENCE_NETWORK"],"countries": null,"displayFormat": "DCO","title": "{{product.name}}","caption": "troponiniq.com","linkUrl": "https://…","linkDescription": null,"adText": "Always Intelligent, Never Artificial","adTextIsTemplate": false,"ctaText": "Sign up","ctaType": "SIGN_UP","videoUrl": null,"imageUrl": "https://…","categories": ["UNKNOWN"],"gatedType": "ELIGIBLE","containsSensitiveContent": false,"containsDigitalCreatedMedia": false,"disclaimerLabel": null,"collationId": "2432929267140392","collationCount": 1,"currency": null,"spend": null,"impressionsText": null,"reachEstimate": null,"transcriptStatus": null,"transcript": null,"hook3s": null,"hookStartSeconds": null,"language": null,"durationSeconds": null,"segments": null,"chargeEvents": {"adRow":1,"transcript":0,"surchargeMinutes":0},"sourceIndex": 1,"#k": "ad:1507887230933843","#ce": {"ad-row":1}}
How often the data changes
Meta's Ad Library updates continuously: new ads appear within hours of going live, and an ad's isActive and endDate change the day an advertiser stops it. For competitor monitoring a daily run is the useful cadence; for a market survey, weekly. The spend, impressions and reach bands on EU political ads move slowly — monthly is enough. Video and image URLs are signed by Facebook's CDN and expire within hours to days, so fetch the creative soon after the run, or re-run to get fresh links.
What one run can reach
Each keyword or advertiser page returns at most searchMaxAds ads (default 25; up to 500 per keyword — ask for more and the run continues at 500) and the whole run at most maxAds (default 100; up to 10,000 per run — ask for more and the run continues at 10,000, with one uncharged row saying so). Meta's own search stops serving deep pages a few thousand results in, whatever its counter says — so a broad keyword is better split by country or ad format than pushed to a huge cap. The run's status line and its OUTPUT record say exactly what happened: how many ads were listed, how many rows delivered and charged, how many your date filters dropped, and how many sat beyond your cap — never a silent stop. If one search stops short because its pages stopped carrying ads new to the run — usually because another of your keywords had already listed them — an uncharged note row says exactly that, names the run's own limit as the run's own, and never reports it as a verdict about the advertiser.
- Newest ads first? There is no sort control — the Ad Library serves its own order. To get the newest, set
startedAfterto a recent date and leaveactiveStatuson Currently running; the search runs, older ads are dropped uncharged, and the rows that land are the recent ones.
What is never charged
- A search that returns no ads — including a keyword that matches nothing and an advertiser with nothing running in that country.
- A search Facebook walled, rate-limited or refused: it comes back as one uncharged row that says so and can be retried — never as an empty run that looks like success.
- An Ad Library link that will not resolve, or names an ad Meta has removed.
- An ad whose row could not be read from Meta's response.
- Ads dropped by your own
startedAfter/startedBeforewindow (they filter on the ad's start date, after the search) and ads beyond yourmaxAdscap. - With Add the ad's transcript on: a silent or music-only ad, an image ad, an expired video link, and any transcription that failed. The ad row is still delivered; only the transcript goes unbilled.
- A time limit or a cost cap ends the collecting, never the delivering: rows already in hand ship in full, and any that could not be billed ship uncharged and say so.
Pricing
| Event | What it is | Free plan | Business |
|---|---|---|---|
| Ad | One ad row delivered to your dataset. | $0.004 | $0.002 |
| Ad transcript | One video ad transcribed, only with includeTranscript on, only when a transcript is delivered. First 3 minutes included. | $0.020 | $0.010 |
| Long-video minute (surcharge) | One started minute beyond the included first 3 minutes of a transcribed video. | $0.005 | $0.005 |
Platform usage is included in those prices — there is no start fee and no compute bill on top.
Notes
If it earned its keep, a rating helps other buyers find it, and saving the actor keeps it one click away.
Something wrong or missing? Open an issue on this actor's Issues tab and we will answer there.
Unofficial. Not affiliated with, endorsed by, or sponsored by Meta Platforms, Inc.