Meta Ad Library Scraper: Facebook & Instagram Ads
Pricing
from $0.70 / 1,000 ads
Meta Ad Library Scraper: Facebook & Instagram Ads
Scrape Meta's Ad Library by keyword, advertiser Page or Ad Library URL: ad text, headline, CTA, link, image and video URLs, start date, days running and platforms (Facebook, Instagram, Messenger, Threads), plus EU reach and payer on request. Only-new mode for competitor monitoring. No login.
Pricing
from $0.70 / 1,000 ads
Rating
0.0
(0)
Developer
Michael Costa
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
a day ago
Last modified
Categories
Share
What does Meta Ad Library Scraper: Facebook & Instagram Ads do?
Meta Ad Library Scraper pulls ads from Meta's Ad Library (facebook.com/ads/library) for any search term, advertiser Page or Ad Library URL: the ad's text, headline, button, link, image and video URLs, start date, days running and the platforms it ran on (Facebook, Instagram, Messenger, Threads, WhatsApp, Audience Network). On request it adds EU reach, targeting and who paid. Live, logged out; no Facebook account needed.
Input fields · API · Use it from Claude, ChatGPT or Cursor (MCP)
Jump to: Monitor · Fields · Price · How to use · Input · Output · Switching · AI agents (MCP) · Limits · FAQ
Try it in one click: the input comes pre-filled with the search running shoes in every country, 50 ads. That's
50 ads, or about $0.035 (50 × $0.0007, plus $0.00005 for the run start). Then replace it with what you actually
want.
Monitor a competitor's ads: get only new ones, in Slack, email or a webhook
With Only new ads on, each run returns (and charges for) only the ads that search hasn't returned before. A run with nothing new costs only the $0.00005 start fee.
- Put the competitor's Page in Advertiser Pages (
"pages": ["https://www.facebook.com/nike"]), or a keyword in Search terms, turn on Only new ads ("onlyNew": true), and click Start. This first run returns the current ads (up to Max ads per search) and is the baseline. - Click Save as a new task (top right of the actor page). The memory is kept per input line and filter set (the
same Page with another country is a separate search), in the key-value store
meta-ad-library-seenin your account, so the task keeps comparing with its own earlier runs. - In Apify Console, open Schedules, click Create new, set how often in Schedule setup (for example daily at 07:00), then Add your task.
- On the task, open the Integrations tab and pick where the new ads go:
- Slack: click Configure, sign in, pick the workspace and channel, and the "run succeeded" event. A
useful message:
{{resource.statusMessage}}and a link,<https://console.apify.com/storage/datasets/{{resource.defaultDatasetId}}|new ads>. - Gmail: click Connect with Google, set the subject and body, and attach the dataset. It sends after each successful run.
- HTTP webhook: event
ACTOR.RUN.SUCCEEDED, your URL. Apify POSTs{"eventType": ..., "resource": {...}};resource.defaultDatasetIdis the run's dataset, andGET https://api.apify.com/v2/datasets/<defaultDatasetId>/items?format=json(with your API token) returns the new ads.
- Slack: click Configure, sign in, pick the workspace and channel, and the "run succeeded" event. A
useful message:
Apify's integrations fire after every successful run, including quiet ones: a quiet run's dataset is empty.
What data does Meta Ad Library Scraper return?
One row per ad:
| Field | Example | Notes |
|---|---|---|
id, url | 3897259703744748, https://www.facebook.com/ads/library/?id=3897259703744748 | The ad's Library ID and its own Library page |
pageName, pageId, pageUrl | On, 238939146624, https://www.facebook.com/On/ | The advertiser |
text, title | Discover our selection of running shoes..., Running | Primary text and headline (null when the ad has none) |
ctaText, ctaType, linkUrl | Shop now, SHOP_NOW, http://www.on.com/ | The button and where it goes |
imageUrls, videoUrls | ["https://scontent...jpg"] | Every image and video, carousel and catalogue cards included |
cards | [{"title": ..., "linkUrl": ..., "imageUrl": ...}] | Each card of a carousel, dynamic or catalogue ad |
startDate, endDate, daysRunning | 2026-05-06, 2026-10-14, 162 | Long-running ads are usually the ones that work |
isActive, platforms | true, ["facebook", "instagram", "threads"] | |
displayFormat | IMAGE, VIDEO, CAROUSEL, DCO, DPA | DCO is dynamic creative, DPA a catalogue ad |
versions | 3 | How many versions of the same creative Meta groups together |
euTotalReach, euReachBreakdown | 1808715, [{"country": "DE", "ageRange": "25-34", "male": ..., "female": ...}] | With Ad details on, for ads shown in the EU |
payers, advertiser | [{"payer": "...", "beneficiary": "..."}] | With Ad details on |
spend, impressions, reachEstimate | $600K - $700K, >1M | Political and issue ads only; null otherwise. Always US English, whatever country the request comes from |
spendMin, spendMax, currency | 600000, 700000, USD | The spend range as numbers, ready to sort and sum; impressionsMin/Max and reachEstimateMin/Max likewise (>1M gives a min of 1000000 and no max) |
Every result has the same fields; the full list is under Output.
How much does it cost to scrape the Facebook Ad Library?
You pay per ad: $0.70 per 1,000 ads on every Apify plan, plus $0.00005 each time a run starts.
- The example below: 50 ads × $0.70/1,000 = $0.035, plus the start fee.
- A month, for example: watching 20 competitor Pages daily with Only new ads, about 5 new ads per Page a day: 20 × 5 × 30 = 3,000 ads ≈ $2.10, plus 30 run starts ($0.0015) for one daily task.
- Ad details (EU reach, payer, advertiser) cost nothing extra; they make a run slower.
- Caps: Max ads per search and Max results per run in the input, and Maximum cost per run in the run options. The run stops cleanly at whichever comes first, and stops fetching as soon as the limit is covered: the next page is never requested, so a capped run is also a fast one.
Never charged: searches that fail, ads already returned with Only new ads, and rows without an ad ID, Page or link (they're dropped, not written).
How to scrape the Facebook Ad Library
- Open Meta Ad Library Scraper and click Try for free (or Start if you're signed in).
- Fill in Search terms, Advertiser Pages or Ad Library URLs (any mix, one per line).
- Optionally set Country, Active status, Media type, Platforms, the Shown from / until dates, and Ad details for EU reach.
- Click Start, then open the Output tab and export as JSON, CSV or Excel. Ads appear in batches as they're found, not only at the end.
Example: running shoes ads, every country
The pre-filled input:
{"searchTerms": ["running shoes"], "maxAdsPerQuery": 50}
It returned 50 ads, every one with an image or video (local run, 2026-10-14). One of them, a catalogue ad with 6 cards (long values and lists shortened):
{"id": "3897259703744748","url": "https://www.facebook.com/ads/library/?id=3897259703744748","query": "running shoes","queryType": "keyword","pageId": "238939146624","pageName": "On","pageUrl": "https://www.facebook.com/On/","pageLikes": 1272558,"isActive": true,"startDate": "2026-05-06","endDate": "2026-10-14","daysRunning": 162,"platforms": ["facebook", "instagram", "audience_network", "messenger", "threads"],"displayFormat": "DPA","title": "Running","text": "Discover our selection of running shoes and apparel built to go the distance.","caption": "on.com","linkUrl": "http://www.on.com/","ctaText": "Shop now","ctaType": "SHOP_NOW","imageUrls": ["https://scontent-phl2-1.xx.fbcdn.net/v/t39.35426-6/672676316...", "..."],"videoUrls": [],"cards": [{"title": "Running","text": "Discover our selection of running shoes and apparel built to...","linkUrl": "https://www.on.com/en-ph/products/weather-jacket-m-1me1031/m...","ctaText": "Shop Now","imageUrl": "https://scontent-phl2-1.xx.fbcdn.net/v/t39.35426-6/672676316..."},"..."],"versions": null,"euTotalReach": null,"scrapedAt": "2026-10-14T22:34:43.441630Z"}
On Apify, the same input took 11 s.
Input
| Field | What it does |
|---|---|
Search terms (searchTerms) | Words to search ads for, one search per line. An ad's Library ID finds that ad. |
Advertiser Pages (pages) | Page address (https://www.facebook.com/nike), Page ID (15087023444) or an Ad Library address with view_all_page_id. |
Ad Library URLs (adLibraryUrls) | Addresses copied from the Ad Library after searching there, or a single ad's (?id=...). Their filters win; the input fills in what they leave out. |
Country (country) | Two-letter code (US, GB, DE...) or ALL (the default). UK is read as GB; the Ad Library has no EU-wide filter. |
Active status (activeStatus) | active (the default), inactive or all. |
Ad category (adType) | all (the default), political_and_issue_ads, housing_ads, employment_ads, financial_products_and_services_ads. |
Media type (mediaType) | all, image, video, meme, image_and_meme, none. |
Platforms (platforms) | Any of facebook, instagram, messenger, audience_network, threads, whatsapp. |
Search terms match (searchMode) | any_words (the default) or exact_phrase. |
Shown from / until (dateFrom, dateTo) | Ads shown in that window (YYYY-MM-DD), Meta's own date filter. |
Max ads per search (maxAdsPerQuery) | Per input line; default 50. Meta lists the most recent ads first. |
Max results per run (maxResults) | Cap across every search. |
Ad details (includeDetails) | EU reach, EU targeting, payer and beneficiary, advertiser info. One extra request per ad. |
Only new ads (onlyNew) | Only ads this search hasn't returned before (how). |
{"searchTerms": ["meal kit"],"pages": ["https://www.facebook.com/HelloFresh.de", "15087023444"],"adLibraryUrls": ["https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&q=protein%20bar&search_type=keyword_unordered&media_type=video"],"country": "DE","activeStatus": "active","platforms": ["instagram"],"dateFrom": "2026-09-01","maxAdsPerQuery": 200,"includeDetails": true}
Output
Every result has the same fields. Fields the Ad Library doesn't show for an ad are null (or an empty list). A real
video ad from a German search URL with Ad details on (local run, 2026-10-14; long links shortened):
{"id": "2186988382220454","adArchiveId": "2186988382220454","url": "https://www.facebook.com/ads/library/?id=2186988382220454","query": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=DE&media_type=video&q=hellofresh&search_type=keyword_unordered","queryType": "url","pageId": "161205527314747","pageName": "HelloFresh","pageUrl": "https://www.facebook.com/HelloFresh.de/","pageProfilePictureUrl": "https://scontent-phl2-1.xx.fbcdn.net/v/t39.35426-6/825286349...","pageLikes": 2519793,"pageCategories": ["Food Service"],"isActive": true,"startDate": "2026-10-02","endDate": "2026-10-14","daysRunning": 13,"platforms": ["facebook", "instagram", "threads"],"displayFormat": "VIDEO","title": "Spare bis zu 120 €","text": "Gewöhnlicher Feierabend, genialer Geschmack. Spar bis zu 120 € & lass uns wieder Abendessen!","caption": "https://www.hellofresh.de","linkUrl": "https://www.hellofresh.de/pages/cook-this-big-idea","linkDescription": "Mit dem Code DEB2S131","ctaText": "Order now","ctaType": "ORDER_NOW","imageUrls": [],"videoUrls": ["https://video-phl2-1.xx.fbcdn.net/o1/v/t2/f2/m366/AQP6PFoMbUN9...mp4"],"videoPreviewImageUrls": ["https://scontent-phl2-1.xx.fbcdn.net/v/t39.35426-6/825286412...jpg"],"cards": [],"versions": 1,"collationId": "28744967888449010","categories": [],"containsAiContent": false,"spend": null,"spendMin": null,"spendMax": null,"reachEstimate": null,"reachEstimateMin": null,"reachEstimateMax": null,"impressions": null,"impressionsMin": null,"impressionsMax": null,"currency": null,"targetedCountries": [],"euTotalReach": 1808715,"euTargeting": {"locations": [{"name": "Germany", "type": "countries", "excluded": false}], "ageMin": 18, "ageMax": 65, "gender": "All"},"euReachBreakdown": [{"country": "DE", "ageRange": "18-24", "male": 21629, "female": 122222, "unknown": 2674}, "..."],"payers": [{"payer": "HelloFresh SE", "beneficiary": "HelloFresh SE"}],"advertiser": {"pageAlias": "HelloFresh.de", "pageCategory": "Food delivery service", "likes": 2519793, "verification": "BLUE_VERIFIED", "instagramUsername": "hellofreshde", "instagramFollowers": 215056, "instagramVerified": true, "about": "HelloFresh liefert Dir Kochboxen mit kreativen Rezepten und saisonalen Zutaten frisch zu Dir nach Hau..."},"scrapedAt": "2026-10-14T22:21:51.291350Z"}
- Image and video links are Meta's CDN addresses, which expire after some days: download what you want to keep (for example with Bulk Image Downloader).
startDateandendDateare Meta's days in Pacific time, as the Ad Library shows them. For a running ad,endDateis Meta's latest day (usually today) anddaysRunningcounts to it.idis stable across runs, so you can use it to deduplicate. The run'sRUN_STATSrecord lists every input line, how many ads it returned, the Ad Library address of that search (searchUrl) and anything that failed, with the reason.
Switching from another Ad Library actor?
Most Ad Library tools take the same things the Ad Library's own page does, under other names. Here's where each one goes:
| What you had | Put it here |
|---|---|
A list of Ad Library search URLs (facebook.com/ads/library/?...) | Ad Library URLs (adLibraryUrls), as they are; their country, status, media, platform and date filters are kept |
| Facebook Page URLs, or "page ads" | Advertiser Pages (pages): the address, the numeric Page ID, or an Ad Library view_all_page_id address |
| Keywords | Search terms (searchTerms); exact phrase with Search terms match (searchMode: "exact_phrase") |
A single ad's link (?id=...) or ad ID | Ad Library URLs, or the ID as a Search terms line |
| A limit per URL or per Page | Max ads per search (maxAdsPerQuery) |
| An overall count or "max items" | Max results per run (maxResults); the maximum cost per run in the run options holds too |
Country code or ALL | Country (country) |
| Active / inactive / all | Active status (activeStatus) |
| A date period, or "newer than" / "older than" | Shown from / Shown until (dateFrom, dateTo), as dates |
| "Scrape ad details", EU reach, transparency | Ad details (includeDetails: true) |
| Proxy settings | Nothing to set: the actor picks its own connection |
What's different in the output: one flat row per ad with camelCase fields (pageName, text, ctaText,
linkUrl, imageUrls, videoUrls, startDate as a date) instead of Meta's raw snapshot object; card media is
listed with the ad's own; daysRunning is computed for you. To reshape rows or rename columns for a sheet, run the
dataset through Dataset Transformer.
Run it on a schedule, or from your own code
- Save your input as a task (Save as a new task, top right of the actor page) and add it to a schedule (Console → Schedules → Create new).
- Collect results: download the dataset as JSON, CSV or Excel; fetch the latest run's results from the
API
(
GET https://api.apify.com/v2/actor-tasks/<task id>/runs/last/dataset/items?status=SUCCEEDED&format=csv, with your API token); let a webhook tell your system when a run succeeds; or connect it to Make, Zapier or n8n through Apify's integrations.
Can I use Meta Ad Library Scraper from an AI agent (MCP)?
Yes, through Apify's MCP server, from Claude, ChatGPT, Cursor or any other MCP client. Add this to your client's MCP configuration (or let the agent find it with the server's actor search); your client signs you in to Apify:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=humble-echidna/meta-ad-library"}}}
To use an Apify API token instead of signing in, add
"headers": {"Authorization": "Bearer <APIFY_TOKEN>"} next to url.
An agent should pass what it's looking for and a small cap, e.g.
{"pages": ["https://www.facebook.com/allbirds"], "country": "US", "maxAdsPerQuery": 20} or
{"searchTerms": ["protein powder"], "mediaType": "video", "maxAdsPerQuery": 30}.
Who it's for
Performance marketers and agencies studying competitors' creatives and offers, media buyers looking for long-running (proven) ads in a niche, e-commerce and DTC brands watching rivals launch new ads, researchers and journalists tracking political, housing or employment ads, and AI agents that need ad copy and creatives on demand.
Why this one?
- Limits that hold. Max ads per search, Max results per run and your maximum cost per run all stop the run before the next page is fetched, so a run never bills past what you set.
- Media for every kind of ad. Carousel, dynamic-creative and catalogue ads come with their card images and videos
in
imageUrls/videoUrls, not just single-image ads. In the example above, all 50 ads had media. - EU reach and payer included in the price. Turn on Ad details for EU reach by country, age and gender, EU targeting, payer and beneficiary, and the advertiser's Page and Instagram figures, at no extra charge.
- Filters apply everywhere. A pasted Ad Library URL keeps its own filters and takes your date range, platforms and the rest where it says nothing.
- Only new ads for monitoring, remembered per search, and
daysRunningto spot ads that have run for months. - Fast, no browser. It reads the data the Ad Library page loads: 500 ads took 111 s on Apify (2026-10-14).
- Reliable. One failing search never affects the others in your run. The run log and the
RUN_STATSrecord say exactly which input line had a problem and why.
Limits
- What the Ad Library shows logged out, nothing more. Spend, impressions and reach estimates exist only for political and issue ads; EU reach and targeting only for ads shown in the EU. No interest or custom-audience targeting (Meta doesn't publish it).
- Page addresses are matched through the Page's ads. Logged out, Facebook shows no Page ID, so a Page address
(
facebook.com/somebrand) is turned into its ID by finding the Page among the Ad Library's advertisers: by its address, or, when the address has changed, by its exact name if only one advertiser has that name (RUN_STATSsays which, aspageMatchedBy). If that fails (two Pages with the name, Pages with no ads), the line fails with the reason: paste the numeric Page ID instead (on the Page: About > Page transparency). - Media links expire after some days (Meta's CDN). Download what you need to keep.
- Only new ads stops a search after 3 pages in a row with nothing new, since Meta lists the most recent ads first; a new ad Meta ranks below that isn't returned until it moves up.
- If Meta changes how the Ad Library page loads its data, searches fail with a message saying so until the actor is updated.
FAQ
Is it legal to scrape the Facebook Ad Library?
The Ad Library is Meta's public transparency archive: anyone can open it without an account. This actor reads the
same public data the Ad Library page loads in a browser, logged out: it never signs in, uses no account, cookie or
session, and solves no captcha or bot check. Please note: facebook.com's robots.txt disallows automated access for
every crawler, and Meta's automated-data-collection terms ask for its written permission; those terms bind people
who agree to them as Facebook users, and in Meta v. Bright Data (N.D. Cal., January 2024) the court held that
Meta's terms didn't cover logged-out collection of public data. The actor identifies itself honestly (User-Agent
HumbleEchidnaApify) and keeps a modest pace. The data is about ads and the Pages that run them; political ads can
name the people who paid for them. How you use the data, including any personal data, is up to you and the laws that
apply to you (GDPR in the EU). If you're Meta or an advertiser and want something taken down, open an issue.
Is there an official Meta Ad Library API?
Yes, but it needs a Facebook account that has passed Meta's identity confirmation, plus a developer app, and it covers political and issue ads worldwide and ads shown in the EU and UK: ordinary commercial ads that ran only elsewhere (most US ads) aren't in it. This actor covers every ad the Ad Library website shows, with no account.
Why did a search return nothing, or fewer ads than expected?
Usually the filters leave nothing (an inactive status with a recent date range, a platform the advertiser doesn't use)
or the Page address couldn't be matched to a Page ID (the reason is in the log; paste the ID). If Meta rate-limits
a connection, the search moves to a fresh one before giving up. The run log and the RUN_STATS record name the input
line and what happened; every other search in the run is unaffected and failed searches aren't charged. Please open
an issue with the input you used if it keeps happening.
Can I get only new results since my last run?
Yes: turn on Only new ads (how).
Can I download the ad images and videos?
The rows carry the image and video addresses. To save the files, send the dataset to Bulk Image Downloader, or download them in your own code before the links expire.
Related actors
| Actor | Use it when |
|---|---|
| Bulk Image Downloader | You want the ad images saved before Meta's links expire |
| Website Change Monitor | You also want to know when a competitor's landing page changes |
| Google Trends Scraper | You want to see whether interest in what they advertise is rising |
| Dataset Diff | You want ads added and removed between two runs, not just new ones |
| Dataset Transformer | You want the results flattened into a CSV or Excel sheet your way |
Feedback and support
Found a bug, or need a field or filter that isn't here? Open an issue on the Issues tab with the input you used.
Versions
Current version: 0.1. See the Changelog tab for what changed in each version.