Meta Ads Library Scraper (Facebook Ads) avatar

Meta Ads Library Scraper (Facebook Ads)

Pricing

from $0.60 / 1,000 ad results

Go to Apify Store
Meta Ads Library Scraper (Facebook Ads)

Meta Ads Library Scraper (Facebook Ads)

For creative strategists, copywriters, media buyers, marketers, and agencies. Scrape the Meta Ad Library by exact phrase, keyword, page, or Library URL. Control country, status, media type, platforms, dates, and impressions sort. $0.60 per 1,000 ads. No Facebook token.

Pricing

from $0.60 / 1,000 ad results

Rating

0.0

(0)

Developer

Arkis

Arkis

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Security

Limited permissions

Share

This Actor is for creative strategists, copywriters, media buyers, marketers, agencies, and anyone watching competitors in the Meta Ad Library (Facebook Ad Library, covering Facebook, Instagram, Messenger, Audience Network and Threads).

When the job is Meta ads, this is the scraper you reach for. You search by keyword (any word or exact phrase), paste an Ad Library URL, or point it at a Facebook page. You pick the country, keep active ads or include inactive ones, filter by media type and publisher platform, bound a delivery window, and sort by impressions or recency. Turn on ad details when you need payer, beneficiary, and EU reach. The inputs stay stable enough to schedule as a monitor.

You get the ad copy, headline, CTA, landing page, image and video URLs, carousel cards, platforms, start and end dates, days running, and, where Meta discloses them, payer, beneficiary and EU reach. Output is clean JSON, CSV or Excel, with no Facebook login, access token or app review.

It works as a Facebook Ad Library API alternative. The official Ad Library API only covers political/issue ads and EU-delivered ads, and it needs identity verification. This Actor reads the same public pages you see at facebook.com/ads/library.

What can it do?

  • 🔎 Keyword search: any-word or exact-phrase, in one country or ALL countries.
  • 🔗 Paste Ad Library URLs straight from your browser. Their filters (country, status, media type, sort, dates, language, platform) are kept.
  • 🏷️ All ads from a page: Facebook page URL, profile.php?id=…, numeric page ID or view_all_page_id= URL.
  • 🎯 Single ad by …/ads/library/?id=<adArchiveId>.
  • 📅 Delivery window and platforms: first-class startDateMin / startDateMax (Meta's delivered-impressions window) and publisherPlatforms (Facebook, Instagram, Messenger, Audience Network, Threads).
  • 🧾 Ad details (on by default): payer, beneficiary, EU total reach and EU audience (age, gender, locations), Instagram handle and followers, page verification.
  • 🖼️ Creatives: image URLs, HD and SD video URLs, video thumbnails, and every carousel / dynamic-product card in snapshot.cards.
  • 💾 Durable media save (saveMedia, off by default): download images and videos into the run key-value store and keep Apify URLs that outlast signed Meta CDN links.
  • 📡 Monitor mode: schedule the same query and only write ads not seen for that fingerprint. Optional emitAdChanges writes itemType: "ad-change" when copy, CTA, landing URL, media, status, platforms or dates shift.
  • ♻️ Deduplicated by adArchiveId across all your queries. You never pay twice for the same ad in a run.
  • 🛟 Resilient: solves Meta's JS challenge, retries with exponential backoff, rotates proxy sessions on blocks, and resumes after migrations. Every run writes a summary to the OUTPUT record.

How to scrape the Meta Ad Library

See the input tab for every field. Four starting points:

1. Competitor page watch

Paste the competitor's Facebook page (or an Ad Library view_all_page_id= URL). Sort by most recent, keep ads active, and schedule the run. Use mode: "monitor" if you only want ads that were not seen for this query before.

{
"urls": ["https://www.facebook.com/BachaCoffeeOfficial/"],
"country": "SG",
"activeStatus": "active",
"sortBy": "most_recent",
"maxAds": 100,
"scrapeAdDetails": true,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

2. Keyword exact-phrase winners

Lock the phrase so you are not matching every word in any order. Sort by impressions to see what actually ran at scale.

{
"keywords": ["best running shoes"],
"searchType": "keyword_exact_phrase",
"country": "US",
"activeStatus": "active",
"sortBy": "impressions",
"mediaType": "all",
"maxAds": 150,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

3. Creative strategist swipe file

Pull video (or image) ads for a theme, optionally on Instagram only, and keep details on so you can see who paid when Meta discloses it.

{
"keywords": ["skincare routine"],
"searchType": "keyword_exact_phrase",
"country": "GB",
"mediaType": "video",
"publisherPlatforms": ["instagram"],
"sortBy": "impressions",
"activeStatus": "active",
"maxAds": 80,
"scrapeAdDetails": true,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

4. Agency multi-country

Set country to ALL, or paste one Ad Library URL per market so each URL keeps its own country filter. Bound a delivery window if you only care about a flight.

{
"urls": [
"https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&view_all_page_id=22437985072&search_type=page",
"https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=GB&view_all_page_id=22437985072&search_type=page",
"https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=DE&view_all_page_id=22437985072&search_type=page"
],
"startDateMin": "2026-01-01",
"maxAds": 200,
"scrapeAdDetails": true,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

A pasted Library URL already carrying country, start_date, or publisher_platforms keeps those values. The fields above fill in anything the URL leaves blank.

5. Scheduled monitor with durable creatives

{
"urls": ["https://www.facebook.com/BachaCoffeeOfficial/"],
"country": "SG",
"activeStatus": "active",
"sortBy": "most_recent",
"maxAds": 80,
"mode": "monitor",
"emitAdChanges": true,
"saveMedia": true,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

The first monitor run saves matching ads (charged as ad) and records their ids. Later runs only write unseen ads. With emitAdChanges, later runs also write itemType: "ad-change" when snapshotted fields move. saveMedia stores files in the run key-value store and adds savedImageUrls / savedVideoUrls.

Pricing

Pay per result. Two add-ons stay off unless you turn them on.

EventDefaultPriceWhen it charges
adalways$0.0006 ($0.60 / 1,000)Each unique ad written to the dataset
media-saveoff (saveMedia)$0.0015 ($1.50 / 1,000)Each ad that had at least one image or video saved to the run key-value store
ad-changeoff (mode: "monitor" and emitAdChanges)$0.0008 ($0.80 / 1,000)Each previously seen ad whose snapshotted fields changed

Failed downloads, duplicate ads, and unchanged previously seen ads are free. The first monitor run with emitAdChanges only stores snapshots; it does not charge ad-change. Basic imageUrls / videoUrls stay in the ad item even when saveMedia is off.

You also pay Apify's standard Actor start event. Set a maximum cost per run in Apify Console and the Actor stops cleanly when the limit is reached.

Adsad onlyAll 1,000 ads also saved media
100$0.06$0.21
1,000$0.60$2.10
10,000$6.00$21.00

Input

FieldTypeDefaultNotes
keywordsstring[]["coffee"] (prefill)One query per keyword. Pair with searchType.
urlsstring[]–Ad Library URLs, Facebook page URLs, page IDs or single-ad URLs.
countrystringSGISO-2 code (US, GB, DE, …) or ALL.
activeStatusactive / inactive / allactive
mediaTypeall / image / video / meme / noneall
maxAdsinteger50Per query (each keyword / URL).
sortByimpressions / most_recentimpressionsSame as the site's sort.
searchTypekeyword_unordered / keyword_exact_phrasekeyword_unorderedExact phrase for tight copy/angle hunts.
startDateMinYYYY-MM-DD–Ads that delivered on or after this date.
startDateMaxYYYY-MM-DD–Ads that delivered on or before this date.
publisherPlatformsstring[]–facebook, instagram, messenger, audience_network, threads. Empty = all.
modesearch / monitorsearchmonitor only writes ads not stored for this query fingerprint (named store meta-ads-library-monitor, cap 20,000 ids).
emitAdChangesbooleanfalseMonitor only. Emit itemType: "ad-change" when snapshotted creative fields change. First run stores snapshots only.
saveMediabooleanfalseDownload creatives into the run key-value store and add durable Apify URLs. Charged as media-save once per ad with at least one saved file.
scrapeAdDetailsbooleantrueOne extra small request per ad for payer/beneficiary/EU fields. Fails soft.
includeRawbooleanfalseAdds the unmodified Meta objects as raw.
paginationFallbackbooleantrueSee Limitations.
proxyConfigurationproxy{ "useApifyProxy": true }Use the RESIDENTIAL group when maxAds > 30.

Output

One dataset item per unique ad (and, if you asked for them, ad-change rows). The dataset has views for Overview, Creatives & media, Payer, beneficiary & EU reach, and Ad changes.

FieldDescriptionAvailability
adArchiveId, adLibraryUrlAd Library ID and public linkalways
pageId, pageName, pageProfileUrl, pageProfilePictureUrl, pageLikeCount, pageCategoriesAdvertiser pagealways (likes may be null)
primaryText, headline, description, ctaText, ctaType, linkUrl, linkCaptionAd copy & destination. For dynamic product ads ({{product.name}} templates) the first card's real text is usedwhen the ad has them
displayFormatIMAGE, VIDEO, CAROUSEL, DPA, DCO, MULTI_IMAGES, …always
imageUrls, videoUrls (HD + SD), videoPreviewImageUrlsMedia of the ad and all its cardswhen present. fbcdn URLs are signed and expire after about 1-4 days
savedMedia, savedImageUrls, savedVideoUrls, mediaStoreIdDurable copies in this run's key-value store (media/{adArchiveId}/…)only with saveMedia, and only for files that downloaded
itemType, changes, beforead or ad-change, plus the field diffsitemType/changes/before when emitAdChanges is on
publisherPlatformsFACEBOOK, INSTAGRAM, AUDIENCE_NETWORK, MESSENGER, THREADSalways
startDate, endDateISO dates. For active ads endDate is the latest delivery date (≈ today)always
isActive, daysRunningDays from start to today (active) or to end datealways
collationId, collationCountGroup of near-identical versions ("N ads use this creative")usually
impressionsText, impressionsIndex, spend, currency, reachEstimateOnly disclosed by Meta for political/issue ads (and some regions); null for normal commercial adsrarely
payer, beneficiary, payerBeneficiaryWho paid / who benefitswith scrapeAdDetails, for ads that reached the EU or fall under regional disclosure rules
targetsEu, euTotalReach, euAudienceEU DSA transparency: total EU reach, gender, age range, locationswith scrapeAdDetails, EU-delivered ads
instagramUsername, instagramFollowers, pageVerificationFrom the details endpointwith scrapeAdDetails
country, keyword, sourceUrl, foundVia, scrapedAtQuery context. foundVia = ssr / pagination / fallbackalways
snapshotCleaned creative: body, title, images, videos, cards[] for carousels / DPA, extra texts/linksalways
rawUnmodified Meta dataonly with includeRaw

Sample item

Real output from a run with keywords: ["coffee"], country: "SG" (long URLs shortened):

{
"adArchiveId": "27086586400970202",
"adLibraryUrl": "https://www.facebook.com/ads/library/?id=27086586400970202",
"pageId": "114040321562599",
"pageName": "Muse App",
"pageLikeCount": 965,
"pageProfileUrl": "https://www.facebook.com/100088641745631/",
"pageCategories": ["Photo & Video"],
"primaryText": "Easy Reels Maker! ✨ Try it now!",
"headline": "Muse: Best Reels Maker",
"description": null,
"ctaText": "Install now",
"ctaType": "INSTALL_MOBILE_APP",
"displayFormat": "VIDEO",
"linkUrl": "http://itunes.apple.com/app/id1638320348",
"linkCaption": "itunes.apple.com",
"imageUrls": [],
"videoUrls": [
"https://video-iad3-1.xx.fbcdn.net/o1/v/t2/f2/m366/AQMVY5oW3u…",
"https://video-iad3-1.xx.fbcdn.net/o1/v/t2/f2/m412/AQO2-5UGzc…"
],
"publisherPlatforms": ["FACEBOOK", "INSTAGRAM", "AUDIENCE_NETWORK", "MESSENGER", "THREADS"],
"startDate": "2026-06-13T07:00:00.000Z",
"endDate": "2026-11-05T08:00:00.000Z",
"isActive": true,
"daysRunning": 146,
"collationId": "1306591561637611",
"collationCount": 1,
"impressionsText": null,
"impressionsIndex": -1,
"spend": null,
"currency": null,
"payer": "BIGROWTH LTD",
"beneficiary": "BIGROWTH LTD",
"targetsEu": true,
"euTotalReach": 739152,
"euAudience": {
"gender": "All", "ageMin": 20, "ageMax": 65,
"locations": [
{ "name": "Worldwide", "type": "country_groups", "excluded": false },
{ "name": "Africa", "type": "country_groups", "excluded": true }
]
},
"instagramUsername": "muse.templates",
"instagramFollowers": 433982,
"pageVerification": "NOT_VERIFIED",
"detailsFetched": true,
"country": "SG",
"keyword": "coffee",
"foundVia": "ssr",
"scrapedAt": "2026-11-05T08:50:06.405Z",
"snapshot": {
"displayFormat": "VIDEO",
"body": "Easy Reels Maker! ✨ Try it now!",
"title": "Muse: Best Reels Maker",
"videos": [{ "videoHdUrl": "https://video-iad3-1…", "videoSdUrl": "https://video-iad3-1…", "videoPreviewImageUrl": "https://scontent-iad6-1…" }],
"cards": []
}
}

Run summary (OUTPUT key-value record)

Each run writes:

  • ads saved per query, and Meta's reported total for the query
  • pages fetched, and whether pagination was blocked
  • how many ads came from each source (foundVia)
  • per-query errors
  • detail-fetch stats
  • media-save stats (files saved / failed) when saveMedia is on
  • monitor fingerprint, previously seen count, and change stats when mode is monitor
  • HTTP stats: requests, retries, blocks by type, session rotations
  • the GraphQL doc_ids used

Limitations

Read these before running large jobs:

  • Meta throttles pagination. The first ~30 results of every search come embedded in the page and are reliable. Further pages need Meta's AdLibrarySearchPaginationQuery, which Meta often answers with Rate limit exceeded for logged-out traffic from datacenter IPs. The Actor backs off and rotates proxy sessions; RESIDENTIAL proxy gives the best chance.
  • Pagination fallback. If pagination stays blocked and paginationFallback is on, the Actor re-runs the first results page over narrower slices of your search. A slice can be a content language, media type, platform, past month, or the other sort order. In tests this raised a no-proxy run from 30 to 300 unique ads for "coffee" in Singapore. All ads still match your filters, but:
    • the extra ads are not in your chosen sort order;
    • the fallback cannot reach every ad of a query with tens of thousands of results;
    • foundVia: "fallback" marks these ads.
  • Spend, impressions and reach are mostly null. Meta only publishes them for political/issue ads, plus EU reach for EU-delivered ads (needs scrapeAdDetails).
  • Media URLs expire. Signed Meta CDN links last about 1-4 days. Turn on saveMedia if you need copies in the run key-value store (charged as media-save). Those files last as long as the run storage does.
  • Monitor baseline is what this Actor fetched, not the entire Ad Library. The first mode: "monitor" run records every ad it actually saw (up to pagination / fallback). Later runs emit ads that were not in that set. Ids are stored in meta-ads-library-monitor, keyed by a hash of keywords, urls, country, status, media type, search type, dates and platforms, and capped at 20,000.
  • Political & issue ad type (ad_type=political_and_issue_ads) may need a logged-in session on some countries; this Actor does not log in.
  • Page URLs by vanity name (facebook.com/SomeBrand) are resolved to a page ID on a best-effort basis. If that fails, use an Ad Library URL with view_all_page_id=.
  • Meta changes its internal web API without notice. The doc_ids are discovered from the live page and fall back to known values. Expect occasional breakage; please report issues.

The Actor only collects data that Meta publishes openly in its Ad Library for transparency, and it never logs in. You are responsible for how you use the data, including any personal data, under GDPR and other laws, and for complying with Meta's terms.

Coming later

These already work if you paste an Ad Library URL that sets them. They are not first-class input fields yet:

  • Content language (content_languages on a Library URL)
  • Ad type, including political and issue ads (ad_type= on a Library URL). Some countries may need a logged-in session for that filter; this Actor does not log in.
  • A list of countries in one keyword search, without using ALL or one URL per market

FAQ

Do I need a Facebook account or API token? No.

Why did I get only ~30 ads? Pagination was blocked. Switch the proxy to RESIDENTIAL and keep paginationFallback on. The OUTPUT record shows paginationBlocked per query.

Can I monitor competitors? Yes. Set mode: "monitor" on a scheduled run with the same keywords or page URLs. The Actor only writes ads it has not stored for that query fingerprint. Turn on emitAdChanges if you also want rows when an already-seen ad changes copy, CTA, landing URL, media, status, platforms or dates.

How do I keep creatives after the CDN links expire? Set saveMedia to true. Files land in the run key-value store under media/{adArchiveId}/… and the dataset item gets savedMedia plus savedImageUrls / savedVideoUrls. You pay media-save once per ad that stored at least one file.