Facebook Ads Library Scraper | Meta Ads by Keyword & Advertiser avatar

Facebook Ads Library Scraper | Meta Ads by Keyword & Advertiser

Pricing

from $1.50 / 1,000 results

Go to Apify Store
Facebook Ads Library Scraper | Meta Ads by Keyword & Advertiser

Facebook Ads Library Scraper | Meta Ads by Keyword & Advertiser

Search the Meta Ad Library by keyword, advertiser page or pasted search link - any country, active or past ads. Each ad returns its archive ID, advertiser, dates, platforms, ad text, CTA and media links. Failed searches are not charged. Export JSON, CSV or Excel.

Pricing

from $1.50 / 1,000 results

Rating

0.0

(0)

Developer

Philip Kirkbride

Philip Kirkbride

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

13 hours ago

Last modified

Features

Limited permissions

Share

Facebook Ads Library Scraper

Search the Meta Ad Library (facebook.com/ads/library) the way you do on the site: type a keyword, open an advertiser's page of ads, or paste a search link you already filtered. Every ad comes back as one clean row with its Ads Library ID and link, the advertiser's name, page and like count, the dates it started and stopped running, the platforms it runs on (Facebook, Instagram, Messenger, Audience Network, Threads, WhatsApp), the ad text, headline, link, call to action and format, plus links to its images, videos and carousel cards.

Results page through automatically up to your limit, so one search can return hundreds of ads instead of the first screen. No Facebook account is needed.

Use cases

  • Competitor ad research: list every ad a competitor is running right now, with the text, offer, landing page and call to action they test.
  • Creative inspiration: collect ads for a keyword or niche and study the hooks, formats and media that keep running for months.
  • Market and trend monitoring: re-run the same searches on a schedule and see which advertisers start, stop or scale campaigns.
  • Lead generation: find businesses that advertise in your market, with their page links and landing pages.
  • Political and issue ad tracking: collect ads with their paid-for-by line, and spend and impression ranges where the Ads Library publishes them.

Quick Start

{
"searchTerms": ["running shoes"],
"country": "US",
"activeStatus": "active",
"maxItemsPerSearch": 50
}

Every ad of one advertiser, in every country, running or stopped:

{
"pageIds": ["15087023444"],
"country": "ALL",
"activeStatus": "all",
"maxItemsPerSearch": 200
}

Input

InputTypeDefaultMeaning
searchTermsarray—Keywords to search ad text for, as you would type them in the Ads Library search box. Each term is one search.
pageIdsarray—Numeric advertiser page IDs. Each one lists that advertiser's ads. You find the ID in an Ads Library link after view_all_page_id=.
adLibraryUrlsarray—Search or advertiser links copied from facebook.com/ads/library. The filters inside a link are applied to that link; a filter the actor cannot reproduce is refused instead of dropped (see Pasted Ads Library links).
countrystringUSTwo-letter country code where the ads were shown (US, GB, DE, BR...), or ALL for every country.
activeStatusstringactiveactive (running now), inactive (stopped) or all.
mediaTypestringallall, image, video, meme, image_and_meme or none (ads without an image or video).
maxItemsintegeremptyOptional total ad limit across all searches; empty means no extra run-wide limit.
maxItemsPerSearchinteger100Stop each search after this many ads, up to 5,000.

You can mix search terms, page IDs and links in one run. Ads already returned by an earlier search in the same run are not repeated.

Empty input runs a small example on its own: {} collects up to 10 ads for running shoes (US, active), and the status message and run summary (usedExample: true) say it was the example. A search field left empty on purpose ({"searchTerms": []}) stops at once with a message naming it. Add your own search to collect what you need instead.

A pasted link is reproduced exactly or refused with an explanation. It is never turned into a broader search than the one you filtered, so you are never charged for rows you did not ask for.

Link parameterWhat the actor does
country, active_status, media_typeApplied to that link; they override the form's values.
q with search_type=keyword_unordered (the default)A keyword search for the term.
view_all_page_id with search_type=pageThat advertiser's ads.
ad_type=allApplied to that link; it is the only ad type this actor reproduces.
is_targeted_country=falseIgnored: it is the Ads Library default and the value the actor already uses; any other value is refused.
fbclid, ref, ref_id, locale, session_id, load_date, sort_data[...], the utm_source/utm_medium/utm_campaign/utm_term/utm_content/utm_id campaign keys and the usual share/tracking keys (mibextid, rdid, share_url, __cft__[...], __tn__)Ignored: tracking, locale and display order cannot change which ads match. An unfamiliar key is refused rather than skipped as tracking.

Only filters this actor has verified are applied; the rest are refused rather than passed on as a guess, because a wrong guess would silently run a different search. These links are refused with an error that says what to change:

  • an exact-phrase search (search_type=keyword_exact_phrase): remove search_type= from the link to search the words as a keyword search, or run the phrase search yourself;
  • ad_type other than all, publisher_platforms[...] and content_languages[...]: remove them from the link, then filter the returned rows if needed (categories for special ad categories, publisherPlatforms for where each ad runs);
  • the date range (start_date[...], end_date[...]) and excluded_ids: remove them, or filter the returned rows by startDate/endDate;
  • is_targeted_country set to anything but false;
  • any other parameter the actor does not know as a filter;
  • an advertiser link that also carries a keyword (q=), because this actor cannot combine a keyword with an advertiser link — paste the keyword as a search term instead;
  • a keyword search_type on a link with view_all_page_id, or search_type=page without one;
  • a single-ad link (?id=...);
  • the same filter twice with different values.

Example queries

  • {"searchTerms": ["meal kit", "protein powder"], "maxItemsPerSearch": 300}: up to 300 running US ads for each keyword.
  • {"searchTerms": ["solar panels"], "country": "GB", "mediaType": "video"}: video ads about solar panels shown in the UK.
  • {"pageIds": ["15087023444"], "activeStatus": "all", "country": "ALL"}: the advertiser's full ad history across countries.
  • {"adLibraryUrls": ["https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=DE&q=versicherung&search_type=keyword_unordered&media_type=all"]}: a search you set up on the site, pasted as is.

What it returns

The dataset contains one row per ad:

FieldMeaning
kindad for every dataset row.
adArchiveId, adLibraryUrlThe Ads Library ID of the ad and its link in the Ads Library.
pageId, pageName, pageProfileUrl, pageProfilePictureUrlThe advertiser's page.
pageLikeCount, pageCategoriesPage likes and categories, as shown with the ad.
isActive, startDate, endDateWhether the ad is running, the date it started and the date it stopped (or the latest date it was seen running), YYYY-MM-DD.
publisherPlatformsWhere it runs: facebook, instagram, messenger, audience_network, threads, whatsapp.
displayFormatIMAGE, VIDEO, CAROUSEL, DCO (dynamic creative), DPA (product catalog) and so on.
body, title, linkDescription, captionThe ad text, headline, link description and the domain shown on the ad.
linkUrl, ctaText, ctaTypeWhere the ad leads and its call-to-action button.
imagesImage links, each with originalUrl and resizedUrl.
videosVideo links, each with hdUrl, sdUrl and previewImageUrl.
cardsCarousel and catalog cards, each with its own title, body, linkUrl, linkDescription, caption, ctaText, ctaType and image or video links.
collationId, collationCountShared ID and count when several ads use the same creative.
categoriesSpecial ad categories (for example POLITICAL, HOUSING) when declared.
containsSensitiveContentWhether the Ads Library marks the ad as sensitive; null if not published.
spend, currency, impressions, reachEstimateRanges published for political and issue ads; empty for other ads.
disclaimerThe paid-for-by line, when the ad carries one.
searchTerm, searchPageId, searchCountry, searchUrlThe search this row came from.
scrapedAtCollection time (UTC).

The run summary (OUTPUT) lists each search with the number of ads and pages returned and how it ended:

FieldMeaning
adsAds this search delivered, after removing ads an earlier search already returned.
pagesResult pages it read.
duplicatesAds it matched that the run had already returned.
completetrue only when the search reached the end of its results, so nothing is missing.
stopReasonnull when complete; otherwise maxItemsPerSearch (its own limit), maxItems (the run-wide limit), chargeLimit (your maximum charge), safetyStop (the source stopped making progress) or error.
errorNO_RESULTS (nothing matched), NO_NEW_ADS (the search reached the end of its results and everything it matched was already returned by an earlier search in this run), SAFETY_STOP, or the source's error code. A search stopped by a limit, a charge stop or an error before the end of its results leaves error empty rather than claim its matches were all delivered; stopReason says what stopped it.

OUTPUT.searchesComplete and OUTPUT.searchesIncomplete count the searches that reached the end of their results and those stopped by a limit, a charge stop, a safety stop or an error. OUTPUT.stoppedBy records the run-wide reason, and OUTPUT.skippedSearches lists searches not attempted, which are not charged. OUTPUT.usedExample is true when empty input ran the prefilled example search. Searches that failed or stopped early are also listed in OUTPUT.searchErrors with the number of ads they delivered before stopping. After three searches in a row are refused or slowed down without returning ads, or when the run cannot renew access, it stops.

Output example

{
"kind": "ad",
"adArchiveId": "1702938977100376",
"adLibraryUrl": "https://www.facebook.com/ads/library/?id=1702938977100376",
"pageId": "15087023444",
"pageName": "Nike",
"pageProfileUrl": "https://www.facebook.com/nike/",
"pageProfilePictureUrl": "https://scontent-phl2-1.xx.fbcdn.net/v/t39.35426-6/431756959_712871054375981_n.jpg",
"pageLikeCount": 39500444,
"pageCategories": ["Sportswear", "Product/service"],
"isActive": true,
"startDate": "2025-04-07",
"endDate": "2026-10-19",
"publisherPlatforms": ["facebook", "instagram", "audience_network", "messenger"],
"displayFormat": "DPA",
"body": "Bring sports more fully into your day with the Nike App.",
"title": "{{product.name}}",
"linkUrl": "http://itunes.apple.com/app/id1095459556",
"linkDescription": null,
"caption": "itunes.apple.com",
"ctaText": "Install now",
"ctaType": "INSTALL_MOBILE_APP",
"images": [],
"videos": [],
"cards": [
{
"title": "Nike Run Swift 3 Women's Road Running Shoes",
"body": "Bring sports more fully into your day with the Nike App.",
"linkUrl": "https://www.nike.com/ph/t/run-swift-3-road-running-shoes-2fHbzp/DR2698-002",
"linkDescription": "₱3,995",
"caption": "itunes.apple.com",
"ctaText": "Install Now",
"ctaType": "INSTALL_MOBILE_APP",
"originalImageUrl": "https://scontent-phl2-1.xx.fbcdn.net/v/t39.35426-6/431679131_949214166636263_n.jpg",
"resizedImageUrl": "https://scontent-phl2-1.xx.fbcdn.net/v/t39.35426-6/431679131_949214166636263_s600x600.jpg",
"videoHdUrl": null,
"videoSdUrl": null,
"videoPreviewImageUrl": null
}
],
"collationId": null,
"collationCount": null,
"categories": [],
"containsSensitiveContent": false,
"spend": null,
"currency": null,
"impressions": null,
"reachEstimate": null,
"disclaimer": null,
"searchTerm": null,
"searchPageId": "15087023444",
"searchCountry": "ALL",
"searchUrl": "https://www.facebook.com/ads/library/?active_status=all&ad_type=all&country=ALL&media_type=all&search_type=page&view_all_page_id=15087023444",
"scrapedAt": "2026-10-20T05:41:00+00:00"
}

Image and video links are shortened here; real links are longer and expire after some days, so download media you want to keep soon after the run.

Good to know

  • Results come in the Ads Library's own default order; a sort order pasted in a link is ignored. Matching does not depend on that order, but a run capped by maxItemsPerSearch or maxItems returns the first ads in the default order, not the top ads for another sort. Keyword searches match ad text, so broad words return many advertisers.
  • title and body of catalog ads (DPA) can hold placeholders such as {{product.name}}; the real product names are in cards.
  • Spend, impressions and reach are only published by the Ads Library for political and issue ads (and some regulated regions); they are empty otherwise.
  • Ads already returned by an earlier search in the same run are skipped, so overlapping searches do not return duplicates. A search keeps paging past those duplicates, however many pages they fill, and still reaches its later new ads; only a search that reaches the end of its results with nothing new is reported as NO_NEW_ADS.
  • If the source keeps repeating a page or serves page after page of ads that search has already seen, that search stops as SAFETY_STOP with complete: false instead of claiming it finished.
  • If a search stops early, the ads it already returned are kept and the reason is shown in the run summary. If no search returns any ad because of an error, the run fails with a clear message instead of finishing empty. A search with no matching ads is reported in the run summary as no results and is not charged.
  • maxItemsPerSearch goes up to 5,000 ads per search. Large searches take a few minutes per thousand ads.
  • Automated access is subject to Meta's terms; use this actor only where you have the necessary permissions and a lawful basis.

FAQ

Why did I get fewer ads than my limit? A search stops when the Ads Library reaches the end of its results for that keyword or advertiser, and a search with no matches returns zero ads and is not charged. Broad words return many advertisers; narrow or misspelled words can match nothing.

How do I list every ad of one advertiser? Paste the numeric page ID into pageIds (the number after view_all_page_id= in an Ads Library link), or paste the advertiser link itself into adLibraryUrls. Set country to ALL and activeStatus to all for the full history.

Why are spend, impressions and reach empty? The Ads Library publishes those ranges only for political and issue ads (and some regulated regions). For all other ads the fields stay null.

Why did an image or video link stop working? Media links are signed and expire after some days. Download the media you want to keep soon after the run.

What does empty input do? It runs the example search (running shoes, US, active ads, up to 10) so a first run shows real rows immediately; the status message and OUTPUT.usedExample say it was the example. Setting any search term, page ID, link or limit uses your input instead; an empty search list is an input error.

Can I run this daily? Yes. Schedule the run with the same searches and compare startDate/endDate between runs, or read the dataset through the Apify API and export it as JSON, CSV or Excel. The run summary tells you which searches finished completely and which stopped at a limit.

What does a failed search cost? Nothing. Searches that fail or return no matches are not charged, and the run summary is free; only delivered ads are billed.

Pricing

$0.0015 per ad returned plus a $0.00125 start event per run; the Pricing tab has the current rates. The start event is charged per GB of memory, so the default 2048 MB run is two start events.

What a run costs: the Console's sample input (one keyword search, up to 50 ads) returns up to 50 rows, about $0.078 in total — $0.075 in ad charges plus the $0.0025 start. A smaller first run with maxItemsPerSearch: 10 costs about $0.018. Searches that fail are not charged, and the run summary is free. Start with a small maxItemsPerSearch and check the run cost before scheduling larger collections.