Meta Ads Library Scraper - Ad Library, All Filters
Pricing
from $0.50 / 1,000 ad delivereds
Meta Ads Library Scraper - Ad Library, All Filters
Meta Ad Library scraper for competitor ads across the whole Meta Ads Library: Facebook, Instagram, Messenger, Audience Network, WhatsApp and Threads, by keyword, page, ad ID or URL. Every website filter, a free total count, hard caps and a memory for new ads only. JSON, CSV, API. Pay per ad.
Pricing
from $0.50 / 1,000 ad delivereds
Rating
5.0
(5)
Developer
Automation Craft
Maintained by CommunityActor stats
6
Bookmarked
88
Total users
58
Monthly active users
a day ago
Last modified
Categories
Share
Meta Ads Library Scraper - Ad Library, All Filters
Meta Ads Library Scraper: search the Meta Ad Library (Facebook, Instagram, Messenger, Audience Network, WhatsApp and Threads ads) by keyword, advertiser page, ad ID or a pasted Ad Library URL, apply every filter the Ad Library website has, and export the ads as clean JSON, CSV or Excel. No login, no cookies, no API keys, no code, and you pay only for the ads you receive.
Built around the complaints buyers leave on other Ad Library scrapers:
- Every Ad Library filter, applied on Meta's side. Country (all 250 plus "All countries"), ad category (all, political, housing, employment, financial), active status, media type, platform, ad language, impressions date window, sort order, "targeted at country", and the political-only filters: paid-for-by, delivery region and estimated audience size. Filters that Meta applies are filters you do not pay for.
- A cap that is honoured, billing that matches it.
maxAdsandmaxAdsPerQueryare hard caps. You are charged exactly once per delivered ad; duplicates, filtered-out ads, total counts, summaries and empty runs are free. - A free total count before you pay. Tick "Only count matching ads" and you get the Ad Library's own total per query at no cost, so you can size a job first.
- Honest coverage. Every query ends with
totalCount,delivered,coverage(complete,partial,empty) andstopReason(cap,end_of_results,thin_pages,blocked). You are told when the data is incomplete instead of guessing. - EU and political transparency, parsed into columns. Political ads carry spend, impressions and audience-size ranges as numbers; "Fetch ad details" adds EU (DSA) reach by country, age and gender, political age / gender and region distributions, payer / beneficiary data and the advertiser profile (page likes, Instagram followers, lifetime spend by disclaimer).
- Free cross-run memory. Name a memory and later runs return only ads you have not received yet. Schedule it and you have a change feed of a competitor's new ads.
- Derived "winning ad" filters, free. Minimum days running, minimum creative reuse (collation count), creative format, text must / must not contain, exclude pages.
- Who is behind a page, optional. "Page details" adds, per advertiser page, when it was created, each name change with its date, the countries its admins are in, the confirmed owner where Meta shows one, and how many ads it runs right now. A page created last month, renamed four times and run from abroad stands out at a glance.
- The exact page a name matched, optional. "Page match" saves which page each advertiser name was matched to, how, and the other pages it could have been, so you can pin the right page ID and stop paying for ads from a lookalike page.
Filter by placement (Facebook, Instagram, Messenger, Audience Network, WhatsApp, Threads) or leave it empty for every Meta surface.
Quick start (30 seconds)
- Type one or more Keywords (one per line), or paste advertiser pages (facebook.com/nike, a page ID, an Instagram profile), advertiser names, Ad Library URLs (every parameter in the URL is applied) or Ad IDs.
- Pick the Countries and any Ad Library filters you would use on the website.
- Set Max ads. Start. Download JSON, CSV or Excel from the Dataset tab, or read it through the API.
Active status matters for cost. The default, activeStatus: "all", returns ads that are no longer running as well as live ones, as the Ad Library does, and every delivered ad is charged. For live ads only, pick "Active ads only" (activeStatus: "active"); on a big brand that is often a small part of the total. Tick "Only count matching ads" (free) to see both numbers first.
Prices in one line: $0.50 per 1,000 ads delivered, plus $0.25 per 1,000 for ad details and $0.20 per 1,000 for resolved landing pages, so $0.75 per 1,000 for an ad with details. Duplicates, filtered-out ads and total counts are free. Full breakdown below.
What you get
One item per ad. Nested objects (images, videos, cards, details) for developers, flat columns (imageUrls, spendLower, landingDomain, ...) for spreadsheets. IDs are strings (they exceed JavaScript's number range).
| Field group | Fields |
|---|---|
| Identity | adArchiveId, adLibraryUrl, adId, collationId, collationCount (how many ads share this creative), pageId, pageName, pageProfileUrl, pageProfilePictureUrl, pageLikeCount, pageCategories |
| Status and timing | isActive, startDate, endDate, daysRunning, totalActiveTimeSeconds, publisherPlatforms |
| Creative | displayFormat (IMAGE, VIDEO, CAROUSEL, MULTI_IMAGES, DCO, DPA, TEXT), adText, title, caption, linkDescription, ctaText, ctaType, images[] / imageUrls, videos[] (HD, SD, preview) / videoUrls, cards[] (carousel items with their own text, link and media), extraTexts, extraLinks, extraImageUrls, extraVideoUrls, allText |
| Destination | linkUrl (as served), landingUrl (l.facebook.com wrappers unwrapped), landingDomain, landingUtm, linkIsTemplate (catalogue placeholders such as {{product.name}}), landingResolved when resolution is on |
| Transparency (political) | isPolitical, adCategories, byline (paid for by), disclaimerLabel, spendText / spendLower / spendUpper, currency, impressionsText / impressionsLower / impressionsUpper, audienceSizeText / audienceSizeLower / audienceSizeUpper, transparencyScope (POLITICAL, EU_DSA, NONE) |
| Flags | containsDigitalCreatedMedia (AI disclosure), containsSensitiveContent, isAaaEligible, gatedType, hideDataStatus, stateMediaRunLabel, hasUserReported, regionalRegulation, brandedContent, ecCertificates, brazilTaxId |
| Details (optional) | details.advertiser (page alias, category, likes, verification, Instagram handle and followers, lifetime and weekly spend by disclaimer, entity type), details.eu (targetsEu, totalReach, reachByCountry[], reachBreakdown[] by country x age x gender, age / gender / location targeting), details.political (ageGender[], regions[] with share, singleCountry), details.payerBeneficiary[], details.isAdTakenDown, details.violationTypes |
| Provenance | searchTerm, searchCountry, searchAdType, queryKey, scrapedAt, changeType (NEW, UPDATED, DUPLICATE), isKnown, firstSeenAt, lastSeenAt, contentHash, charged |
Which transparency numbers exist depends on the ad, not on this Actor: Meta publishes spend, impressions and audience size only for ads in the "Issues, elections or politics" category, and EU reach breakdowns only for ads that were shown in the EU. For every other ad those fields are null and transparencyScope says why. Measured fill rates from live runs at build time:
| Field | Commercial ads (US, keyword) | Political ads (US) |
|---|---|---|
adText | 98% | 100% |
title | 79% | 82% |
linkUrl | 93% | 78% |
landingDomain | 92% | 78% |
ctaType | 93% | 77% |
imageUrls | 40% | 10% |
videoUrls | 25% | 55% |
pageLikeCount | 98% | 97% |
spendText | 2% | 100% |
impressionsText | 2% | 100% |
audienceSizeText | 2% | 98% |
byline | 2% | 98% |
collationCount | 80% | 93% |
endDate | 100% | 100% |
Output
type: "ad" items, type: "count" rows in count mode, type: "status" rows when something could not be done (never charged), and one type: "run-summary" item at the end with per-query totalCount, delivered, pages, coverage, stopReason, the resolved advertisers, dedup stats, exact charges, proxy statistics and fill rates.
With "Page match" on, the run's key-value store also holds a RESOLVED_PAGES record: for each advertiser name, the page ID and name it matched, how it matched (page_alias, page_name, instagram_username or first_suggestion) and the other pages the Ad Library suggested, with their likes, verification and Instagram handle.
Sample item from a live run:
{"type": "ad","adArchiveId": "1785179045778580","adLibraryUrl": "https://www.facebook.com/ads/library/?id=1785179045778580","adId": null,"collationId": "974017695598335","collationCount": 1,"isActive": false,"startDate": "2026-05-07T07:00:00.000Z","endDate": "2026-06-29T07:00:00.000Z","daysRunning": 53,"totalActiveTimeSeconds": null,"pageId": "721404351056614","pageName": "IControl: Easy Widgets Themes","pageProfileUrl": "https://www.facebook.com/61578892468353/","pageProfilePictureUrl": "https://scontent-lga3-2.xx.fbcdn.net/v/t39.35426-6/695177587_1511487320476777_920753808075...","pageLikeCount": 4501,"pageCategories": ["Topic"],"pageIsDeleted": false,"publisherPlatforms": ["FACEBOOK","INSTAGRAM","AUDIENCE_NETWORK","MESSENGER","THREADS"],"displayFormat": "IMAGE","adText": "❤️Aesthetic presets for your phone✨","title": "🥰a FREE and personalized APP for you","caption": "play.google.com","linkDescription": null,"linkUrl": "http://play.google.com/store/apps/details?id=com.icontrol.easy.widgets.themes","landingUrl": "http://play.google.com/store/apps/details?id=com.icontrol.easy.widgets.themes","landingDomain": "play.google.com","landingUtm": null,"linkIsTemplate": false,"ctaText": "Install now","ctaType": "INSTALL_MOBILE_APP","images": [{"url": "https://scontent-lga3-3.xx.fbcdn.net/v/t39.35426-6/689490050_1634784394244050_406178336346...","resizedUrl": "https://scontent-lga3-2.xx.fbcdn.net/v/t39.35426-6/691720374_1271927545153646_343053186879..."}],"imageUrls": ["https://scontent-lga3-3.xx.fbcdn.net/v/t39.35426-6/689490050_1634784394244050_406178336346..."],"videos": [],"videoUrls": [],"videoPreviewImageUrls": [],"cards": [],"cardCount": 0,"extraTexts": [],"extraLinks": [],"extraImageUrls": [],"extraVideoUrls": [],"allText": "❤️Aesthetic presets for your phone✨\n🥰a FREE and personalized APP for you\nplay.google.com","adCategories": ["UNKNOWN"],"isPolitical": false,"byline": null,"disclaimerLabel": null,"spendText": null,"spendLower": null,"spendUpper": null,"currency": null,"impressionsText": null,"impressionsLower": null,"impressionsUpper": null,"impressionsIndex": -1,"audienceSizeText": null,"audienceSizeLower": null,"audienceSizeUpper": null,"transparencyScope": "NONE","targetedOrReachedCountries": [],"countryIsoCode": null,"gatedType": "ELIGIBLE","isAaaEligible": true,"containsDigitalCreatedMedia": false,"containsSensitiveContent": false,"hideDataStatus": "NONE","stateMediaRunLabel": null,"hasUserReported": false,"reportCount": null,"isReshared": false,"brandedContent": null,"event": null,"brazilTaxId": null,"additionalInfo": null,"ecCertificates": [],"regionalRegulation": {"finserv": {"is_deemed_finserv": false,"is_limited_delivery": false},"tw_anti_scam": {"is_limited_delivery": false}},"searchTerm": "nike","searchCountry": "US","searchAdType": "ALL","queryKey": "term:nike:US","scrapedAt": "2026-09-01T18:30:38.204Z","changeType": "NEW","isKnown": false,"firstSeenAt": "2026-09-01T18:30:38.204Z","lastSeenAt": "2026-09-01T18:30:38.204Z","charged": true}
How much does it cost to scrape Meta ads?
You pay per event, never per hour, and every price below is the current base price on this listing.
| Charge event | What triggers it | Price |
|---|---|---|
Ad delivered (ad-result) | One ad record delivered to the dataset | $0.50 per 1,000 |
Ad details fetched (ad-details) | Advertiser profile, EU (DSA) reach breakdown, political age / gender / region insights and payer data for one ad, when "Fetch ad details" is on | $0.25 per 1,000 |
Landing page resolved (landing-page-resolved) | Final landing URL and domain after redirects, when "Resolve landing pages" is on, charged only when a page answered | $0.20 per 1,000 |
Actor Start (apify-actor-start) | Apify's standard start event, once per run per gigabyte of memory (on this listing from 22 September 2026). This Actor defaults to 256 MB, so it is one event per run | $0.05 per 1,000 runs ($0.00005 per run) |
Two optional events, off unless you turn them on, are charged from 23 October 2026 (before that date both options work and are free):
| Optional event | What triggers it | Free / Bronze | Silver | Gold |
|---|---|---|---|---|
Page details (optional) (page-details) | Once per advertiser page per run whose details came back, when "Page details" is on | $2.50 per 1,000 pages | $2.25 | $2.00 |
Page match (optional) (page-match) | Once per advertiser name that matched a page, when "Page match" is on; names without a match are free | $0.60 per 1,000 names | $0.55 | $0.50 |
Platinum and Diamond plans pay the Gold price. The other events above have one price on every plan.
An ad with details costs $0.75 per 1,000 ads.
Always free: duplicates inside a run, ads the memory already knows across runs, ads dropped by the post-filters, the total counts from "Only count matching ads", status rows, the run summary, and a run that finds nothing.
Worked examples (start event included): 500 ads for three keywords = $0.25; 2,000 competitor ads with details = $1.50; a daily re-run under a memory name that finds 8 new ads among 300 known ones = $0.00405; a run that finds nothing = $0.00005.
Input reference
| Input | What it does |
|---|---|
| Keywords, Keyword matching | The Ad Library search box. "Exact phrase" is the quoted search. |
| Advertiser pages, Advertiser names | Page IDs, page URLs, Instagram profiles or plain names (resolved through the Ad Library's own advertiser lookup; the run summary lists the candidates). Returns the page's "See all ads" view. |
| Ad Library URLs | Paste a URL from your browser; keyword, page, country, ad type, status, media type, platforms, languages, dates, sort and political filters are all read from it. ?id= URLs fetch that single ad. |
| Ad IDs | Library IDs to fetch directly (current status, dates, creative, political numbers). Unknown IDs are reported and free. |
| Countries | Any of the 250 countries or All countries. Several countries = one query each (fair share of the cap). EU expands to the 27 member states (API). |
| Ad category | All, political, housing, employment, financial (the regulated categories). Political ads are the ones with spend and impressions. |
| Active status, Media type, Platforms, Ad languages | Exactly the website's filters. |
| Impressions within / from / to | The website's "Impressions by date": ads that were shown in the window (an ad that started earlier and is still running matches). |
| Sort | Default relevance, impressions high to low / low to high, most recent (grouped by launch month), as the website offers. |
| Only ads targeted at the country | The is_targeted_country switch. |
| Paid for by, Delivery regions, Audience size | Political-only filters. Region names as the website shows them ("California"). Audience buckets: 100-1K, 1K-5K, 5K-10K, 10K-50K, 50K-100K, 100K-500K, 500K-1M, above 1M. |
| Minimum days running, Minimum creative reuse, Creative formats, text filters, Exclude pages | Free post-filters. |
| Max ads, Max ads per query | Hard caps on delivered, charged ads. maxItems: 0 through the API means no cap. |
| Only count matching ads | Free preflight: one count row per query, no ads, no charge. |
| Fetch ad details, Resolve landing pages | Paid add-ons, charged only when data came back. |
Page details (optional), fetchPageDetails | Off by default. Adds pageDetails to each ad: pageCreatedAt, nameChangeCount, nameChangedAt, history, adminCountries (country and number of admins), confirmedOwner (name, city, state, postal code, country, phone where Meta shows them), stateMediaLabel, about and activeAdsCount (ads the page runs now in all countries; 50001 means more than 50,000). Read once per page per run. |
Page match (optional), includePageMatches | Off by default. For advertiser names and page handles: the RESOLVED_PAGES run record and matchedAdvertiserName on each ad. The name lookup itself is unchanged and stays free with or without it. |
| Memory name, Also return already-known ads, Reset memory | Cross-run dedup (named key-value store ads-library-memory-v2-<name> in your account). Known ads are never charged. |
Stop after N fully-known pages (maxKnownPages) | Optional, off by default (0). For scheduled change feeds: stop a query after N consecutive result pages that contain only ads the memory already knows (stopReason known_pages), instead of paging to the cap. Cheaper polls; pair it with the "Most recent" sort so new ads are never behind known ones. |
| Proxy, Parallel queries, IP retries, Stop after N empty pages | Advanced. Leave the defaults. |
Using the API
Same input as the form.
curl -X POST "https://api.apify.com/v2/acts/automation_craft~meta-ads-library-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"searchTerms": ["adidas"],"countries": ["US"],"activeStatus": "active","mediaType": "video","publisherPlatforms": ["instagram"],"deliveredWithinDays": "30","maxAds": 100}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('automation_craft/meta-ads-library-scraper').call({advertiserNames: ['Nike'], countries: ['ALL'], fetchAdDetails: true, maxAds: 200, memoryName: 'nike-watch',});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.filter((i) => i.type === 'ad').length, 'ads');
from apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("automation_craft/meta-ads-library-scraper").call(run_input={"searchTerms": ["vote"], "countries": ["US"], "adType": "political_and_issue_ads", "bylines": ["VOTEVETS"], "fetchAdDetails": True, "maxAds": 50,})ads = [i for i in client.dataset(run["defaultDatasetId"]).iterate_items() if i["type"] == "ad"]
Input keys are tolerant: country names or codes, enum labels or ids, lowercase or uppercase, strings or arrays, and the common aliases other scrapers use (keyword, maxItems, startUrls, period, startDateMin) are accepted.
Recipes
- Competitor monitoring: advertiser pages +
memoryName, scheduled daily. Only new ads arrive;changeType: UPDATED(with "Also return already-known ads") flags ads whose status, dates or creative changed. - Winning ads: keyword +
activeStatus: active+minDaysRunning: 30+minCollationCount: 3+sortBy: total_impressions_desc. - Political spend research:
adType: political_and_issue_ads+bylinesorregions+fetchAdDetails: truefor age / gender / region distributions and lifetime spend by disclaimer. - EU DSA audits: an EU country +
fetchAdDetails: truefor reach by country, age and gender and the declared targeting. - Sizing a job: the same input with
onlyTotalCount: truefirst (free). - Vetting advertisers: a keyword such as a product or offer +
activeStatus: active+fetchPageDetails: true. Sort the rows bypageDetails.pageCreatedAtandpageDetails.nameChangeCount: new pages with renamed histories and admins in unexpected countries are the ones to check first. - Pinning the right page: advertiser names +
includePageMatches: trueonce, then copy the page IDs fromRESOLVED_PAGESinto "Advertiser pages" for every later run.
What this Actor does NOT do
- It does not log in and never asks for cookies or tokens, so it only sees what the public Ad Library shows. Spend, impressions and audience size exist for political ads only; EU reach data only for ads shown in the EU. Meta's ranges (">$1M", "100K-500K") are ranges, not exact numbers.
- Very broad keywords: the Ad Library's own result pages thin out after a few hundred ads (
stopReason: thin_pages,coverage: partial). Split the job by country, platform, date window or advertiser page for complete coverage. - It does not download media files; it delivers the CDN URLs (which expire after some days, so download what you need).
- It does not read the aggregate "Ad Library report" spend tables (use Meta Ad Spend Scraper), branded-content listings (use Meta Branded Content Scraper) or the collation "summary" panel.
- Meta rate-limits roughly half of all residential IPs. The Actor rotates IPs automatically and the run summary shows
proxy.blockedIps; a query that cannot get a clean IP is reported ascoverage: blockedand costs nothing.
FAQ
Which platforms does the Meta Ad Library cover?
Facebook, Instagram, Messenger, Audience Network, WhatsApp and Threads. The "Platforms" filter keeps ads that ran on at least one placement you pick; leave it empty for every Meta surface. Every ad carries publisherPlatforms so you can see where it actually ran.
Can I paste a Meta Ad Library URL and get a spreadsheet?
Yes. Drop any facebook.com/ads/library URL into "Ad Library URLs" and every parameter in it is applied: keyword, page, country, ad category, active status, media type, platforms, languages, date range, sort and the political filters. A ?id= URL fetches that single ad. Download the dataset as CSV or Excel from the Dataset tab.
How do I monitor a competitor's new Meta ads automatically?
Put the competitor's page in "Advertiser pages", set a "Memory name" and schedule the run. Ads delivered under that name are remembered, so every later run returns only the ads you have not received yet, and ads the memory already knows are never charged again.
Is there a Meta Ads Library API and what does it cost?
Meta runs its own Ad Library API; this Actor does not use it and never asks you for a token for it. It reads the public Ad Library the way the website does, with no login and no cookies, and you pay Apify $0.50 per 1,000 ads delivered. Tick "Only count matching ads" to see how big a search is before you pay anything.
How fast is it?
Measured on Apify at the default 256 MB on 8 October 2026: the 20 ad example input finishes in 5 to 23 seconds (usually under 10), because the first 30 ads of a search come with the page itself. 100 ads from one keyword took 43 seconds and 300 ads 197 seconds; 300 ads spread over three keywords took 102 seconds, because queries run in parallel ("Parallel queries", default 3). Deep pages of one broad keyword are the slow part, so split big jobs by keyword, country or page. "Page details" added 44 to 60 seconds for 11 to 22 pages (read four at a time).
Does the Actor stop at my limit?
Yes. "Max ads" (maxAds) is a hard cap on delivered and charged ads for the whole run, and "Max ads per query" (maxAdsPerQuery) caps each keyword x country or page x country. Several queries share the total: each gets an equal share first, then unused budget moves to queries that still have results. You never receive or pay for more ads than the cap, and the run summary shows delivered and stopReason: cap per query.
How much will it cost to scrape 1,000 Meta ads?
$0.50 for 1,000 ads as delivered, or $0.75 if you also switch "Fetch ad details" on, plus Apify's start event of $0.00005 for the run itself. Ads your memory already knows, ads your post-filters drop and the free total count are not charged, so a scheduled watch pays only for what is new.
Why does this Actor run with limited permissions?
Least privilege. It only reads and writes its own storages: the run's dataset, and, when you set a memory name, a key-value store it creates itself (ads-library-memory-v2-<your memory name>). It never needs access to the rest of your Apify account, so it does not ask for it, and schedules and API calls do not raise an approval prompt.
Changelog
- 1.3.4: optional settings other than dropdown selects accept an empty (null) value from Zapier, Make or the API and run as if left out.
- 1.3.3: ad ID and ad link lookups work again after Meta changed how it shows a linked ad (14 October 2026).
- 1.3.0: two optional features, off by default: "Page details" (page creation date, name changes, admin countries, confirmed owner, active ads count) and "Page match" (the
RESOLVED_PAGESrecord and the matched name on each ad). Both are charged as listed above from 23 October 2026 (free before that date). Nothing changes for a run that does not turn them on: same inputs, same output, same prices. - 1.1.0: cheaper runs, same results; Apify's standard start event ($0.05 per 1,000 runs) added, every other price unchanged. The first page a run loads now provides the session tokens (no second page load per run); the memory is written only when it changed; runs default to 256 MB (enough for this HTTP-only engine; up to 1024 MB can still be requested); optional
maxKnownPagesfor cheaper scheduled change feeds (off by default). No input or output changes; ad, details and landing-page prices unchanged. - 1.0.0: first release. Keyword, page, advertiser-name, URL and ad-ID modes; every Ad Library filter; exact caps with fair share; free total count; post-filters; cross-run memory; ad details (EU, political, advertiser); landing-page resolution; per-query coverage reporting.
More data tools by Automation Craft
Same engine, other placements:
More Meta transparency data:
- Meta Ad Spend Scraper: Advertiser Spend by Country
- Meta Branded Content Scraper: Paid Partnerships
- Facebook Page ID Finder: Names to Page IDs
Other marketing and ecommerce data: