Facebook Ads Library Scraper - Meta (Facebook) Ad Library avatar

Facebook Ads Library Scraper - Meta (Facebook) Ad Library

Pricing

from $9.00 / 1,000 results

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

Facebook Ads Library Scraper - Meta (Facebook) Ad Library

Extract Facebook & Instagram ads from the Meta Ad Library: ad copy, image and video URLs, CTA links and start dates. Search up to 5 brands or keywords per run, or pin an exact Page ID. Re-run on a schedule and every ad is labelled new, ongoing or ended. No login.

Pricing

from $9.00 / 1,000 results

Rating

5.0

(1)

Developer

jy-labs

jy-labs

Maintained by Community

Actor stats

3

Bookmarked

414

Total users

51

Monthly active users

3 days ago

Last modified

Share

Facebook Ads Library Scraper

Pull Facebook and Instagram ads out of the Meta Ad Library for up to 5 brands or keywords per run. Every ad comes back labelled new, ongoing, or ended against your last run, and you don't need a login.

Input · Output · Pricing · FAQ

What you get

  • Change labels across runs. Re-run the same search on a schedule and each ad is marked new, ongoing, or ended, with firstSeenDate, lastSeenDate and runsSeen. You see what changed instead of the same list again. Set onlyNewAds and a run delivers only the ads it hasn't seen before.
  • One result per advertiser. Set dedupeBy: "advertiser" and Max Results counts distinct accounts, not ads: 200 results means 200 different advertisers, each with an advertiserAdCount.
  • Page ID pinning. Pair a keyword with an advertiser's numeric Facebook Page ID and the search only returns ads from that page.
  • Match evidence on every row. matchedBy shows whether your keyword actually appears in the advertiser name, ad copy or CTA link, or whether Meta only ranked the ad for your query.
  • No login. The Actor doesn't use a Facebook account, cookies or a Meta developer token.
  • Up to 5 keywords per run. They run one after another. Export to JSON, CSV or Excel, or read the results over the Apify API.

Output

Three real rows from a Nike search in the US on 2026-09-29, trimmed to the columns most people read first (body and links shortened):

brandbodystartDatectaLink
Nordstrom RackBuy online and pick up in store for free! Get up to 70% off Nike, Vince…2026-08-03https://fb.com/canvas_doc/1072291375736811
Foot LockerRefresh your wardrobe with new styles from Nike, New Balance, adidas…2026-07-22https://www.footlocker.com/product/~/00051791…
NikeEntra a Nike.com y encuentra actualizaciones semanales de producto con envío…2023-08-15https://www.nike.com/mx/t/calzado-de-golf-…

Each row also includes libraryID, keyword, pageId, brandImg, isActive, platforms, images, videos, scrapeDate, matchedBy and matchEvidence. With change tracking on (the default), rows also include the change labels. The full field list:

FieldTypeDescription
libraryIDstringUnique Meta Ad Library identifier
keywordstring|nullThe keyword you searched; null on ended-ad rows
pageIdstring|nullPage ID used for this search; null if none
brandstringAdvertiser name
brandImgstringAdvertiser profile image URL
bodystringAd copy
startDatestringWhen the ad started running (YYYY-MM-DD)
isActivebooleanWhether the ad is still running
platformsarrayWhere the ad runs: any of Facebook, Instagram, Audience Network, Messenger, WhatsApp, Threads. An "Unknown" entry means an icon could not be identified, so the list may be incomplete
imagesarrayImage URLs (carousels included)
videosarrayVideo URLs with poster images
ctaLinkstringCall-to-action destination URL
matchedBystringpage_id, visible_text, visible_partial or meta_search (see Match evidence)
matchEvidenceobjectWhich extracted fields and terms matched
advertiserAdCountintegerAds this advertiser was running among the ads scanned; only with dedupeBy: "advertiser"
scrapeDatestringWhen the row was collected (ISO 8601)
adStatusstringnew, ongoing, or ended; only with change tracking on
isNewbooleanTrue when no earlier run of this search returned the ad
firstSeenDatestringWhen this monitoring stream first returned the ad
lastSeenDatestring|nullThe previous sighting before this run; null on a new ad
runsSeenintegerHow many runs of this stream returned the ad, including this one

The Console dataset has four views: Overview, Creatives, Changes and Advertisers.

Find long-running (winning) ads

Meta doesn't publish spend or results for commercial ads, but it does publish how long each ad has been running, and advertisers rarely keep paying for an ad that doesn't work.

  1. Run your search with activeStatus: "active" so every row is an ad that is still live.
  2. Sort the dataset by startDate, oldest first.
  3. Look closely at ads that have been active for 60 days or more (scrapeDate minus startDate). These are the creatives the advertiser has kept paying for.

On a scheduled search, runsSeen tells you the same thing from your own history: a high count means the creative has stayed in rotation across many of your runs.

Input

Quick start

  1. Click Try for free to open the Actor in Apify Console.
  2. Switch the input to the JSON tab, paste the input below, and replace Nike with the brand you track.
  3. Click Start. A run like this usually finishes in about two minutes. Export the dataset as JSON, CSV or Excel.
{
"keywords": ["Nike"],
"country": "US",
"activeStatus": "active",
"maxResults": 20
}

Everything else already has a working default. Residential proxy is on, multi-word keywords are matched as an exact phrase, and change tracking labels every row against your previous runs of the same search.

Input fields

The form shows the common fields first. Rarely changed settings are grouped under Advanced.

ParameterTypeDescriptionDefault
keywordsarrayBrand names, products or topics, up to 5 per runRequired
pageIdsarrayOptional numeric Page IDs, matched by position to keywords. Leave an entry blank for keyword-only search. Non-numeric Page IDs are rejected before browser work starts.-
countrystringCountry whose Ad Library is searched (22 countries or ALL). Also sets the residential proxy exit country.US
activeStatusstringall, active, or inactiveall
mediaTypestringall, image, meme, video, or noneall
maxResultsintegerResults per keyword (1–200). Counts advertisers when dedupeBy is advertiser100
adTypestringall or political_and_issue_adsall
startDateMinstringMeta's own date filter: only ads shown on or after this date. Ads that began earlier but were still running are included; check startDate-
startDateMaxstringMeta's own date filter: only ads shown on or before this date, so every ad returned started on or before it-
sortBystringrelevancy_monthly_grouped (Meta's default) or total_impressionsrelevancy_monthly_grouped
searchTypestringexact_phrase (words together, in order) or unordered (any word, anywhere)exact_phrase
dedupeBystringnone or advertiser (one row per account)none
trackChangesbooleanAdd new / ongoing labels against earlier runs. Adds fields only and never filters.true
onlyNewAdsbooleanDeliver only ads this search hasn't returned beforefalse
includeEndedAdsbooleanAlso emit a row for tracked ads that stopped runningfalse

Advanced settings: relevanceMode (balanced / strict / all), monitorKey (names a separate history stream), requestHandlerTimeoutSecs (default 600, the per-keyword ceiling across navigation, readiness checks, scrolling, and extraction), proxy (Apify Proxy, RESIDENTIAL group, which you should leave as it is), blockMediaAssets (default on; skips downloading media bytes but still extracts every URL) and debugMode (saves a final-page screenshot). includeUnverifiedMetaSearchResults is deprecated but still accepted. Use relevanceMode instead.

To pin a keyword to one advertiser, search the advertiser in the Meta Ad Library, open their page, and copy the digits from view_all_page_id=… in the URL. Then line the IDs up by position:

{
"keywords": ["Nike", "Adidas"],
"pageIds": ["", "123456789"]
}

Use cases

  • Competitor monitoring. Schedule a weekly run with onlyNewAds and read the creatives your competitors launched since last week.
  • Creative research. Build a swipe file of ad copy, images and videos, starting with the ads that have run longest.
  • Prospecting. Search the offer you sell against with dedupeBy: "advertiser" and get a list of accounts running it, one row each.
  • Brand and client monitoring. Pin a Page ID and track every ad one advertiser runs in a given country.
  • Market research. Compare what runs for the same keyword in different countries.

Pricing

$10 per 1,000 results on the Free plan, plus a $0.04 start charge per run. From October 12, 2026, Apify also bills platform usage to your account separately.

EventPrice
Result (apify-default-dataset-item)$0.010 per Dataset item, falling to $0.009 on Silver and higher plans ($0.0095 on Bronze)
Actor start (apify-actor-start)$0.02 per GB of allocated memory
Platform usage (compute + residential proxy)Included until October 12, 2026. From October 12, 2026, billed to your account separately at Apify's standard rates

The default 2048 MB memory allocation produces two 1 GB Actor-start events, or $0.04 per run.

Worked examples on the Free plan:

  • 5 results: $0.04 start + 5 × $0.010 = about $0.09
  • 100 results: $0.04 start + 100 × $0.010 = about $1.04

From October 12, 2026, add platform usage to those figures. For scale, a 2-keyword run that returned 8 ads used about $0.03 of platform usage (measured 2026-09-29). Usage grows with the number of keywords and how far each search scrolls, and blockMediaAssets (on by default) keeps it low because media bytes are never downloaded. The run detail page in Apify Console always shows your actual charge.

What counts as a result depends on the options you set. The price per result stays the same:

SettingOne result isYou are billed for
defaultone adevery ad the run delivers
dedupeBy: "advertiser"one advertiserone row per account, not per creative
onlyNewAds: trueone ad that is new to this searchthe delta only; ads already reported are free
includeEndedAds: truealso one ad that stopped runningthose rows too, like any other result

maxResults applies per keyword, so five keywords at 100 results can deliver up to 500 rows. A run that delivers no rows has no result charge, but the start charge still applies (and, from October 12, 2026, platform usage for the time the run took).

FAQ

Do I need a Facebook account, login or API token?

No. The Actor reads the public Meta Ad Library pages, so there is no Facebook login, no account cookies and no Meta developer app or access token. You still get programmatic access through Apify's REST API, webhooks, schedules and integrations such as Google Sheets, Zapier and Make.

How many keywords can I search at once?

Up to 5 per run, processed one after another. Blank entries are dropped, and a sixth non-empty keyword is rejected before the browser starts.

What do new, ongoing, and ended mean?

  • new: no earlier run of this search returned the ad.
  • ongoing: an earlier run already reported it.
  • ended: the ad was tracked and has now been missing for two consecutive runs. One absence isn't counted, because maxResults caps what a run sees and Meta reorders its results.

ended rows appear only when you set includeEndedAds: true.

Why did a run return fewer rows than maxResults?

The run log says which reason applied:

  • the keyword really has fewer ads;
  • the per-keyword time limit ran out (raise requestHandlerTimeoutSecs);
  • relevanceMode: "strict" dropped ads that never show your keyword;
  • dedupeBy: "advertiser" ran into too many repeats from the same accounts.

Does it return ad spend, reach or targeting data?

No. Meta publishes spend and impressions only for political and issue ads, and the Actor doesn't extract per-ad EU reach or targeting figures. The country input picks which country's Ad Library is searched, not the audience an ad declares.

Meta Ad Library publishes advertising data for transparency. Whether a particular collection or use is allowed depends on the applicable terms, laws, jurisdiction and use case. You are responsible for reviewing Meta's terms and getting legal advice when appropriate.

Change monitoring in detail

Change tracking (trackChanges) is on by default. Each search keeps its own history in a key-value store named meta-ad-monitor inside your own Apify account, so nobody else can see it. Deleting that store resets the history. A stream is identified by the search itself (keywords, page IDs, country, ad type, status and media type), so a saved task on a schedule lines up with itself automatically, and keyword order doesn't matter. Set monitorKey if one input needs separate histories, for example one per client.

  • Labels, not filters. trackChanges adds fields and never removes rows. onlyNewAds: true is the filter. The first run returns everything, because everything is new; after that you get only what appeared since. Ads that are filtered out are still recorded, so they are never re-reported as new. If the history can't be read, the run delivers every row rather than none, and says so in the log.
  • Ended ads need includeEndedAds: true. These rows are charged like any other result.
  • Only complete runs update the history. A failed or partial run saw less of the Ad Library than it should have, so it is never folded in. Otherwise a broken run would retire ads that are still running.
  • Overlapping runs merge their results instead of overwriting each other. Still, set the schedule interval longer than one run takes.
  • The run's status message shows the change summary, for example 6 new, 106 ongoing, so you can see it in the run list without opening the run.

Prospecting for advertisers

With dedupeBy: "advertiser", maxResults counts distinct advertisers. For each advertiser the Actor keeps its best-matching ad (deduplication happens after relevance ranking). Deduplication covers the whole run, so an advertiser found under two keywords is still one row, and advertiserAdCount shows how many ads that account was running. The Actor scans further to fill your quota, up to 400 ads per keyword. On free consultation with maxResults: 200, a measured run scanned 423 ads and delivered 200 distinct advertisers.

{
"keywords": ["free consultation"],
"country": "US",
"dedupeBy": "advertiser",
"maxResults": 200
}

Don't combine this with a Page ID. A Page ID search already covers a single advertiser, so deduplication leaves one row.

Match evidence

Meta decides which ads belong to a keyword search and sometimes returns ads whose visible text never mentions it. Every row says how it matched:

  • page_id: the search was pinned to a Page ID, which is the strongest evidence.
  • visible_text: every keyword term appears in the advertiser name, ad copy or CTA URL.
  • visible_partial: some of the terms appear.
  • meta_search: Meta returned the ad, but the extracted fields don't show the keyword.

relevanceMode: "balanced" (the default) fills your quota in that order. strict keeps only page_id and visible_text rows; for slogan-only brands it can return very few, and the log shows a [yield-alarm] warning when that happens. all keeps Meta's order untouched. matchEvidence.phraseMatch ranks exact-phrase hits higher within a tier. visibleMatch: false means the extracted text doesn't prove a match; the keyword can still appear inside the creative image.

Empty results and troubleshooting

Some keywords really do have no ads, and a run that reports that is doing its job. A keyword with zero rows counts as a completed search when the page rendered, Meta showed its no-results text, ad data arrived, or strict relevance removed the candidates. It counts as a failure when Meta refused to serve the search (a challenge page, a verification wall, a JavaScript-disabled shell, or rate limiting), when the page never rendered and neither ad data nor no-results text arrived, or when navigation failed or timed out. The Actor rotates the page and proxy route and retries while time allows. If every keyword fails, SUMMARY.status is failed. A mix of successful and failed keywords gives completed_partial.

Scrolling that stops short of the requested result count because of time limits, rate limiting, or an interruption is also recorded explicitly. Usable rows are still delivered, with a partial keyword status, and any partial keyword makes the run completed_partial. An incomplete keyword that delivers no rows has an error status, for example error: runtime budget exhausted when its scroll ran out of time, and counts as a failed keyword toward failed / completed_partial above. These runs do not advance change history or report newly ended ads. A fulfilled result quota, ordinary pagination exhaustion, and confirmed empty searches remain successful.

To investigate a run, open its Log and search for [diagnostic] to follow each stage from start-up through navigation, scrolling, extraction and dataset writes. The run's key-value store has a DIAGNOSTICS record with the latest 50 events and the first and last failures. Diagnostic records never contain your search text, page IDs, full URLs or ad copy.

What's new

  • 2026-09-29: platforms shows where each ad runs again, after Meta changed how placements are drawn in late September 2026. An icon that cannot be identified is listed as "Unknown" next to the ones that were, so an incomplete list never looks complete.
  • 2026-10-12: Platform usage (compute and residential proxy) will be billed to your Apify account at standard rates instead of being included in the result price. See Pricing.
  • 2026-09-15: Run diagnostics: [diagnostic] log lines and a DIAGNOSTICS record in each run's key-value store.
  • 2026-08-31: The default sort no longer sends Meta its own sort parameters, which had switched some searches to an unrelated feed.
  • 2026-08-24: Multi-word keywords are now searched as an exact phrase. Added one result per advertiser (dedupeBy) and only-new ads (onlyNewAds). Pagination no longer stops early when an ad's text contains "no results".

Something broken? Open an Issue on this page.

Support

This Actor collects publicly visible data from the Meta Ad Library without accessing private accounts. You are responsible for making sure your collection and use of the data comply with Meta's terms and applicable laws.