Facebook Ad Library Scraper avatar

Facebook Ad Library Scraper

Pricing

from $0.70 / 1,000 ads

Go to Apify Store
Facebook Ad Library Scraper

Facebook Ad Library Scraper

Every ad a brand runs on Facebook, Instagram and Threads, from the public Meta Ad Library, logged out. Or check in bulk if pages run Meta ads. Page URL, domain or brand input. $0.70 per 1,000 ads, $1 per 1,000 page checks, no start fee. Never more ads or charges than you asked. Empty searches free.

Pricing

from $0.70 / 1,000 ads

Rating

0.0

(0)

Developer

Otter Fetch

Otter Fetch

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

8 hours ago

Last modified

Categories

Share

Never more ads or charges than you asked for. Empty ad searches are free.

A Facebook Ad Library scraper that works like a simple Meta Ad Library API: give it page URLs, website domains or brand names, and get every ad they run on Facebook, Instagram, Messenger, Audience Network and Threads as flat rows. Use it to track competitor Facebook ads, collect Instagram ads for creative research, or check if a brand runs Facebook ads right now for a lead list. It reads the public Ad Library without logging in. Not affiliated with Meta.

Price: $0.70 per 1,000 ads, $1 per 1,000 page checks. No start fee. Status and summary rows are free. Add-ons: EU details $0.30 / 1k ads with data, media archive $0.50 / 1k ads (images) or $2 / 1k (with video).

What you get

  • Ads mode: one summary row per target ("40 of 5,547 shown"), then one row per ad with text, dates, days running, platforms, format, call to action, landing page, images and videos.
  • Page check mode: one row per page with running yes or no, active ad count, verified flag, likes, Instagram followers and category, built for lead lists.
  • Optional add-ons: EU reach and demographics and media archiving, so image and video links do not expire.

See the same brand's Google ads with our Google Ads Transparency actor.

Why this one

  • Hard limits. maxAdsPerTarget and your maximum cost per run are never exceeded. The Actor works out what it can still pay for before it asks Meta for each page, so a big page never pushes you over.
  • Free when empty. A search with no ads, a blocked target, a skipped target and an unclear domain each give a plain-English status row. None of them is billed.
  • You can see what you did not get. Each target starts with a summary row such as "30 of 4,212 shown", so you know how much more there is before you raise the limit.
  • Exact when you give a page URL. Domains and brand names are matched with a stated confidence, never guessed in silence.
  • Flat output. One row per ad with the text, dates, platforms, landing page, images and videos as plain columns.
  • Media you can keep. Meta's image and video links expire after about 4.4 days. You can archive the files into your run's storage.

Quick start

  1. Pick Mode: Ads or Page check.
  2. Type your Targets, one per line. A Facebook page URL (https://www.facebook.com/nike) is best. A page ID, an Ad Library link, a website domain or a brand name also work. Or paste a CSV or Google Sheets link in Import targets from a link.
  3. Set a country, filters and Max ads per target if you want. The default is 30, which is the fastest and cheapest. The form is prefilled with a small first run.
  4. Click Start. When it ends, open the Overview view or export the dataset as CSV.

What it returns

Every row has type, input, status, row_id and ad_library_url.

  • target_summary (ads mode, one per target, first): the page or query that was used, Meta's full total, how many ads you got, and a label like 30 of 4,212 shown. It also has the format mix, platforms, top landing domains, and match_confidence and match_reason. It is free.
  • ad (ads mode, one per ad): ad ID and link, page, active flag, start and end dates, days running, platforms, display format, body, body_is_template, body_template, title, title_template, link description, call to action, landing URL and domain, images, videos, cards, variant_count, variant_ad_ids, spend and impressions where Meta shows them (political ads), EU data when you ask for it, media_expires_at and archived_media.
  • page_check (page check mode, one per page): page name, ID, URL, verified flag, likes, Instagram name and followers, running_ads, active_ad_count (counts above 50,000 show as 50,000 with count_capped true), the newest start date, the oldest start date in the sample, the format mix, platforms and top landing domains. extraction.page_info says where the verified flag, Instagram fields and category came from (missing when Meta returned none; those fields are then empty).
  • status (free): a reason and a plain message for anything empty or uncertain: invalid_target, page_not_found, domain_low_confidence, no_ads, filters_too_narrow, blocked, failed, meta_changed, skipped_limit, skipped_budget and skipped_timeout.

Example output

Ads mode, Gymshark (maxAdsPerTarget 40):

typepage_nameshown_labelad_idstart_datedays_runningdisplay_formatplatformsbodycta_textlanding_domainvariant_count
target_summaryGymshark40 of 5,547 shown
adGymshark24299772608137662026-08-2856DCOINSTAGRAMSo hot, du wirst es nicht glauben. Hol dir jetzt ...Learn moregymshark.com4
adGymshark15712938476902052026-07-0590VIDEOINSTAGRAMSois ready en ayant la tenue qui te donnera la motivation ...Learn moregymshark.com4
adGymshark13532845897678812026-07-3147VIDEOINSTAGRAMÇa sent une motivation à bloc et de nouveaux PRs ...Learn moregymshark.com3

Page check mode:

inputpage_namerunning_adsactive_ad_countverifiedlikesig_usernameig_followerscategoryextraction.page_info
https://www.facebook.com/nikeNiketrue2,832true39,497,425nike290,912,401Sportswear Storedetails
111126298904665Potato Cornerfalse0true679,893potatocornerph90,587Food Standtypeahead

Two modes

Ads. For each target you get a summary row, then its ads, newest, most relevant or most impressions first (your choice). Page 1 comes back fast (about 30 ads). More ads are fetched page by page until you reach maxAdsPerTarget, and the Actor stops there.

Page check. For each page you get one page_check row that answers: is this page running Meta ads right now, how many, and the newest and oldest start dates among its first ~30 ads. It makes one or two quick lookups per page and never walks through the ads, so it is quick and cheap for lead lists. It always counts active ads, whatever the active status filter says.

Inputs

Page URL first: a Facebook page URL gives exact results. A page ID and an Ad Library link are exact too. Website domains and brand names are matched to a page, and the match comes with a match_confidence (high, medium) and a match_reason. If a domain cannot be matched with enough confidence, you get a free domain_low_confidence row that lists the best candidate pages, so you can pick one and run it by its page URL.

Field (key)What it does
Mode (mode)ads or pageCheck. Default ads.
Targets (targets)One per line: page URL (best), page ID, Ad Library link, website domain, or brand or keyword.
Import targets from a link (importUrl)A CSV or Google Sheets link. First column.
Search brand names as keywords (keywordMode)Off: a brand name is resolved to its page. On: the line is a keyword search across all advertisers.
Country (country)Where the ads ran. Default all countries.
Active status (activeStatus)active, inactive or all. Default active.
Media type (mediaType)all, image, video, meme, image and meme, or none.
Platforms (platforms)Facebook, Instagram, Messenger, Audience Network, Threads.
Language (language)Ad language.
Ran between (dateFrom, dateTo)Ads that were running at any time in this range. An ad that started before the range and was still live inside it is included.
Sort (sort)relevance, impressions (most impressions) or newest.
Max ads per target (maxAdsPerTarget)Hard limit on what is fetched and billed. Default 30. 0 means no limit.
One row per creative (groupVariants)See below.
EU reach and demographics (euDetails)See below.
Archive media (archiveMedia)See below.
Max targets (maxTargets)Safety limit for scheduled runs. Extra targets get a free skipped_limit row.

An Ad Library link keeps its own filters (country, status, media type, platforms, language, dates, sort) for that target.

Fewer, cheaper rows: groupVariants

Advertisers often run the same creative many times with small changes. Turn on One row per creative and you get one row per group of variants, with variant_count and variant_ad_ids. It is billed once per group, so a brand with 200 variants of 20 creatives costs for 20 ads. maxAdsPerTarget then counts rows.

EU reach and demographics: euDetails

For ads shown in the EU or UK, Meta publishes total reach and the age, gender and country breakdown, plus who paid and who benefits. Turn this on to add them in the eu column. It costs $0.0003 per ad, and only for ads where Meta actually returned EU or UK data. Nothing is charged when the option is off, when the ad was not shown there, or when Meta had no data.

Tip: set the country to an EU country (for example France) together with this option. With all countries, the ads shown first are often not EU ads, so few rows get EU data.

Archive media: archiveMedia

Meta's image and video links are signed and stop working after about 4.4 days (media_expires_at tells you the exact time). To keep the files, set Archive media to images (600 px images and video preview frames) or images_videos (also the video file). The files are saved in the run's default key-value store and linked in archived_media. It is billed per archived ad, and not when a download failed.

Archived files follow your Apify storage retention, so they are removed when your plan's retention ends. To keep them longer, copy them somewhere else, for example to your own S3 or Google Cloud bucket.

Template text: body_is_template

Some ads (dynamic creative) hold placeholders in their text, such as {{product.name}}. Meta fills these in per viewer, and the public library shows the placeholder. For these ads body_is_template is true, and body, title and the landing link are taken from the first card of the ad that has real text (the product the ad shows). The raw placeholders stay in body_template and title_template. When no card has real text, the placeholder is kept as written; the Actor never makes up text.

Pricing

Pay per event. You pay for results, not for time. No start fee.

EventPriceCharged when
ad$0.0007One ad row with data was returned. Summary, status and failed rows are free.
page-check$0.001One page was checked and you got its answer. Every verdict is charged, yes or no, including "not running any ads". Pages that could not be checked are not.
ad-eu-details$0.0003On top of ad, only when euDetails is on and Meta returned EU or UK data for that ad.
media-archive$0.0005On top of ad, when at least one image of the ad was stored. Not charged when the download failed.
media-archive-video$0.002On top of ad, when a video file of the ad was stored. Charged instead of media-archive for that ad.

Prices shown are the current list prices. Apify shows the live price on the Actor page.

A page check is billed for its yes-or-no answer. A page that is not running ads still gets a real answer, so it costs the same as a page that is. Empty ad searches in ads mode, status rows, summary rows, blocked or failed lookups and unclear domains are never billed.

What a run costs: 1,000 ads cost $0.70. With EU details on, add up to $0.30 per 1,000 ads, and with images archived add up to $0.50 per 1,000 ads (up to $2 per 1,000 ads instead with videos archived too). 1,000 page checks cost $1.

The Actor respects your maximum cost per run. It prices each ad at the most it could cost with the add-ons you turned on, and leaves the rest of your targets as free skipped_budget rows once the budget is used.

Example inputs

An exact look at one brand:

{
"mode": "ads",
"targets": ["https://www.facebook.com/nike"],
"country": "US",
"maxAdsPerTarget": 30
}

Which of these companies run Meta ads?

{
"mode": "pageCheck",
"importUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit"
}

Fewer rows, with the files saved:

{
"mode": "ads",
"targets": ["jollibee.com.ph"],
"country": "PH",
"groupVariants": true,
"archiveMedia": "images",
"maxAdsPerTarget": 50
}

Limitations

  • No reach or impressions for most ads. For ads that are not political and not shown in the EU or UK, Meta does not show reach or impressions to logged-out visitors, so we cannot return them.
  • Domains and brand names are matched. A domain is matched through the ads that link to it. Marketplaces (Lazada, Shopee), affiliate-heavy sites and brands without a website often cannot be matched with confidence. Those targets are not fetched or billed. Use the page URL for exact results.
  • Large counts stop at 50,000. Meta stops counting at 50,001, so higher counts show as 50,000 (total_ads 50000 with total_capped true and "50,000+" in the summary label, count_capped true on a page check). To get all the ads of a very large advertiser, split the run by date range.
  • Logged-out public data only. The Actor sees what any visitor to the Ad Library sees. It does not log in, and it does not return anything Meta shows only to signed-in users.
  • Meta changes the Ad Library from time to time. If it does, the Actor tries to update itself. Targets it cannot read get a free meta_changed row, and if no target can be read, the run stops before charging and says so.

FAQ

Do I need a Facebook account or cookies? No. The Actor reads the public Meta Ad Library logged out, the same pages anyone can open. It never asks for a login.

Is this the official Meta Ad Library API? No. Meta's official API covers mainly political and issue ads and needs an approved developer account. This Facebook ads scraper reads the public Ad Library website for all ad types and gives you the same kind of structured rows.

Does it include Instagram ads? Yes. Every ad lists its platforms: Facebook, Instagram, Messenger, Audience Network and Threads. Filter by platform in the input or after export.

How do I check if a brand runs Facebook ads? Use Page check mode with a list of page URLs, domains or brand names. Each page gets one row with running_ads, active_ad_count and the page's verified flag, likes and Instagram followers. A page check costs $0.001, including when the answer is "not running any ads".

Why did I get fewer ads than the total Meta shows? You get at most maxAdsPerTarget ads per target (default 30). The summary row says how many exist, for example "30 of 4,212 shown". Raise the limit or set it to 0 for all ads (big brands can have thousands; set a maximum cost per run). Meta also counts some ads it no longer shows.

Can I get spend and impressions? Meta publishes spend and impressions only for political and issue ads, and the Actor returns them for those. For ads shown in the EU or UK, turn on EU details for reach by age, gender and country.

What if I give a website domain instead of a page URL? The Actor finds the page that runs ads for that domain and says how sure it is (match_confidence high or medium). If no page is a clear match, you get a free row listing the closest pages. A page URL is always exact.

Why do image and video links stop working? Meta's media links expire after about 4.4 days. Turn on media archiving to keep copies in your run's storage. The copies follow your Apify storage retention.

How much does a run cost? 1,000 ads cost $0.70. Page checks cost $1 per 1,000. Add-ons: EU details $0.30 / 1k ads with data, media archive $0.50 / 1k ads (images) or $2 / 1k (with video). Set a maximum cost per run and the Actor stops before it, never after. Rows for empty searches, blocked or skipped targets and unclear domains are free.

Will I ever pay for more ads than my limit? No. The Actor trims each page to what you are still owed before it saves the rows, and it charges only after a row is saved.

What happens when my budget runs out mid-target? The Actor delivers as many ads as the budget covers, stops, and marks the remaining targets as skipped. You are never charged beyond your maximum.

What if a run is interrupted? Restarts continue where the run stopped. Charges are never repeated after a restart, but a few free status rows may appear twice.

Can AI agents use it? Yes, through the Apify API or MCP server. Summary rows come first, every row has a type, and status rows explain in plain words why something is empty.

Is this affiliated with Meta? Not affiliated with Meta. Data comes from the public Meta Ad Library.

More from us

See the same brand's Google ads with our Google Ads Transparency actor.

Issues

Report problems in the Issues tab. Include the run link and the target that went wrong.