To scrape the Facebook Ads Library, point a Facebook Ads Library scraper at a Facebook page, a page name or an Ad Library search link, and save each ad as a row: the ad copy, creative, call to action, landing page, start date, platforms and its public Ad Library link. The fastest way is the Facebook Ad Library Scraper on Scrape.ly, which reads the public library without a Facebook login, Meta app or access token, at $0.05 per 1,000 ads.
This guide covers the no-code steps, the API (curl, Python, Node.js and AI agents over MCP), the cost, the limits that come from Facebook itself, and what Meta's official Ad Library API does and doesn't cover. Everything below comes from a real run on 23 October 2026 on Nike's active US ads: the exact input, output, log and charge.
What data you can get from the Meta Ad Library
The Facebook Ad Library Scraper writes one row per ad. These are the fields you'll use most:
| Field | What it holds |
|---|---|
ad_archive_id, ad_library_url | The Ad Library ID and the public page for that ad |
page_name, page_id | The Facebook page that ran the ad |
is_active, start_date_formatted, end_date_formatted | Whether the ad is running, and its dates in UTC |
publisher_platform | Where it ran: Facebook, Instagram, Audience Network, Messenger, WhatsApp, Threads |
snapshot.body.text, snapshot.title, snapshot.cta_text | Ad copy, headline and call to action |
snapshot.link_url, snapshot.caption | Landing page and the domain shown on the ad |
snapshot.display_format, snapshot.cards, snapshot.images, snapshot.videos | Format (image, video, carousel, catalog) and every card, image and video URL |
snapshot.page_like_count, snapshot.page_categories | The page's like count and categories |
pageInfo | Page transparency: creation date, confirmed owner, whether it's running ads |
spend, reach_estimate, aaa_info | Spend and reach (when Meta publishes them) and EU reach and payer details (with Scrape ad details on) |
Facebook fills spend and reach_estimate mainly for ads about social issues, elections or politics, so ordinary commercial ads leave them empty. A URL that can't be read becomes its own row with error and errorCode, and error rows are not charged.
How to scrape the Facebook Ads Library without code
- Open the Facebook Ad Library Scraper in the Scrape.ly Store.
- Pick a ready-made input. We used the preset Nike's active US ads by reach, 10 ads. "Try this input" opens it in the console.
- Swap in the brand you're researching. This is the exact input of our run:
{
"urls": [{ "url": "https://www.facebook.com/nike" }],
"count": 10,
"scrapePageAds.activeStatus": "active",
"scrapePageAds.countryCode": "US",
"scrapePageAds.sortBy": "impressions_desc"
}- Click Start. Ten ads take a few seconds.
- Export the ads as JSON, CSV, Excel or HTML.
The fields that matter most:
urls: three ways in. A Facebook page URL (https://www.facebook.com/nike), a bare page slug (nike), or an Ad Library search link copied from your browser, which keeps its country, keyword, status and media filters.count: ads to save across all URLs. Default 10.limitPerSourcecaps each URL.scrapePageAds.activeStatus,scrapePageAds.countryCode,scrapePageAds.sortBy,scrapePageAds.period: filters for page URLs:active/inactive/all, a two-letter country orALL,impressions_descormost_recent, and ads started in the last 24 hours, 7, 14 or 30 days.scrapeAdDetails: adds EU reach, payer and advertiser fields, one extra request per ad. The preset Shoe ads in Germany with details, 5 ads shows it with a keyword search link.
Scrape the Facebook Ads Library with the API
Create an API token under Settings → API & Integrations and export it as SCRAPELY_TOKEN.
Our run finished in 6 seconds, so the synchronous endpoint fits: it starts the run, waits up to 45 seconds and returns the ads as a JSON array. Add ?format=csv for CSV.
curl -X POST "https://api.scrape.ly/v2/actors/echofield~facebook-ads-library-scraper/run-sync-get-dataset-items" \
-H "Authorization: Bearer $SCRAPELY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urls": [{"url": "https://www.facebook.com/nike"}], "count": 10, "scrapePageAds.activeStatus": "active", "scrapePageAds.countryCode": "US"}'If you add many URLs or switch on ad details and a run takes longer than 45 seconds, the call answers 408 while the run keeps going. Don't call it again (that starts a second run); use a client instead.
Python (pip install scrapely-client-python). This example compares what three brands are running in the US right now, by format and landing domain:
import os
from collections import Counter
from urllib.parse import urlparse
from scrapely_client import ScrapelyClient
client = ScrapelyClient(os.environ["SCRAPELY_TOKEN"], api_url="https://api.scrape.ly")
run = client.actor("echofield/facebook-ads-library-scraper").call(
run_input={
"urls": [{"url": "nike"}, {"url": "adidas"}, {"url": "puma"}],
"count": 90,
"limitPerSource": 30,
"scrapePageAds.activeStatus": "active",
"scrapePageAds.countryCode": "US",
}
)
print(run.status) # SUCCEEDED, FAILED, ABORTED or TIMED-OUT
ads = [a for a in client.dataset(run.default_dataset_id).iterate_items() if not a.get("error")]
for page, n in Counter(a["page_name"] for a in ads).items():
mine = [a for a in ads if a["page_name"] == page]
formats = Counter(a["snapshot"].get("display_format") for a in mine)
domains = Counter(urlparse(a["snapshot"].get("link_url") or "").netloc for a in mine)
print(page, n, dict(formats), domains.most_common(2))Node.js (npm install scrapely-client):
import { ScrapelyClient } from 'scrapely-client';
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN, baseUrl: 'https://api.scrape.ly' });
const run = await client.actor('echofield/facebook-ads-library-scraper').call({
urls: [{ url: 'https://www.facebook.com/nike' }],
count: 10,
'scrapePageAds.activeStatus': 'active',
'scrapePageAds.countryCode': 'US',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((a) => [a.start_date_formatted, a.snapshot.cta_text, a.ad_library_url]));For AI agents, add the Scrape.ly MCP server. In Cursor, put this in ~/.cursor/mcp.json:
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}In Claude Code, run claude mcp add --transport http scrapely https://api.scrape.ly/mcp and sign in with /mcp. Then ask: "Use scrapely to run echofield/facebook-ads-library-scraper on Nike, Adidas and Puma, 30 active US ads each, and summarize which offers and calls to action each brand is pushing." See the MCP docs for other clients. The Facebook Ads Library API page shows the same Actor as a ready API product.
A real run: Nike's active US ads
We ran the "Nike's active US ads by reach, 10 ads" preset on 23 October 2026. It returned 10 ads in 6 seconds and was charged $0.0015. The first five rows:
| Library ID | Started | Platforms | Format | Ad text | First product card |
|---|---|---|---|---|---|
| 1016451784037642 | 2025-06-20 | Facebook, Instagram | DPA | Get the gear that goes hard on and off the field. | Nike Air Monarch IV |
| 1277433457899494 | 2026-10-19 | Facebook, Instagram | DPA | Run through summer with gear that can take the heat. | Nike Tempo Shorts |
| 1849003099878021 | 2026-10-19 | Facebook, Instagram | DPA | Get the gear not afraid to put in the work. | Nike Air Monarch IV |
| 29548096774776782 | 2026-10-19 | Facebook, Instagram | DPA | Get the gear that goes hard on and off the field. | Nike Air Monarch IV |
| 3286219464896203 | 2026-10-19 | Facebook, Instagram | DPA | Run through summer with gear that can take the heat. | Nike Air Monarch IV |
Nike is a business named in the input on purpose, so nothing here needed masking. What the full ten show:
- Catalog ads, not one-off creatives. All ten had
display_format: DPA, a headline template ({{product.name}}) filled from a product feed, and six product cards each: 50 of the 60 cards showed Nike Air Monarch IV shoes and the other 10 Nike Tempo Shorts, every card with its own product URL on nike.com. - A fresh batch plus one long runner. Nine ads started on 19 October 2026; the top one had been running since 20 June 2025. An ad that stays active for 16 months is worth a closer look.
- Four lines of copy, rotated. The ten ads used four distinct body texts ("Get the gear not afraid to put in the work." appeared four times), all with Shop now and all on Facebook and Instagram only.
- Page transparency comes along.
pageInforeported "NIKE, Inc. is responsible for this Page," a page created on 21 May 2008, and the page currently running ads;snapshot.page_like_countwas 39,497,958. - No spend or reach. As expected for commercial ads in the US,
spendandreach_estimatewere empty.
The run's log, without the platform's start-up lines:
2026-10-23T03:01:55.528Z [Scrapely] Container started (setup 1.8 s)
2026-10-23T03:01:56.788Z [scrapely.proxy_configuration] INFO Platform proxy access check succeeded.
2026-10-23T03:01:59.368Z [scrapely.actor] INFO Saved 10 ads
2026-10-23T03:02:00.145Z [Scrapely] Container state: status=exited exitCode=0 oomKilled=false2.6 seconds from the proxy check to ten saved ads, on the default datacenter proxy, with no browser and no Facebook account.
What it costs
The Actor charges one event, $0.00005 per ad saved, which is $0.05 per 1,000 ads. Platform usage (compute and proxy) is billed on top, and for this Actor it's the larger part of a small bill.
For our run: 10 ads × $0.00005 = $0.0005 in ad fees. The run was charged $0.0015 in total, because it also used $0.0008 of compute and $0.0001 of datacenter proxy traffic. Error rows for URLs that can't be read are not charged.
A weekly sweep of 20 competitors at 30 ads each is 600 ads, or $0.03 in ad fees plus usage. The Free plan's $5 of monthly credit covers that many times over. Set Max cost per run in the run options if you want a hard cap.
What to watch out for
- About 30 ads per URL. Facebook shows logged-out visitors only the first page of results, about 30 ads per search or page. The run status says when a URL returned fewer than you asked for. For more, add narrower URLs in the same run: one per country, media type or date range.
- Spend and reach are political-ad fields. Meta publishes spend ranges and reach for ads about social issues, elections or politics. For commercial ads, use start dates, active status and how many variants a brand runs as your signals.
- EU details cost one request per ad.
scrapeAdDetailsadds EU reach, payer and advertiser fields, which is useful for ads delivered in the EU and slower for big runs. - Media links expire. Image and video URLs on Facebook's CDN are signed and stop working after a while. Download the creatives you want to keep soon after the run.
- Templates in catalog ads. Headlines like
{{product.name}}are filled per viewer; read the product names fromsnapshot.cards. - Country codes. An unknown country code in the page filters stops the run with a clear message, and an unknown country inside a pasted link falls back to all countries.
Is it legal to scrape the Facebook Ads Library?
The Ad Library is public by design: Meta built it so anyone can see who is advertising and what they run, and the Actor reads it without logging in. That doesn't settle every question. Meta's Terms of Service (effective January 1, 2025) say: "You may not access or collect data from our Products using automated means (without our prior permission)", and they add that this applies "regardless of whether such automated access or collection is undertaken while logged-in to a Facebook account."
Courts have looked at logged-out scraping of Meta's public pages. In Meta Platforms v. Bright Data (N.D. Cal., January 23, 2024), Judge Edward Chen granted Bright Data summary judgment on Meta's breach-of-contract claims, holding that the Facebook and Instagram terms at issue did not prohibit scraping publicly available data while logged off. That ruling concerned those terms and those facts; it isn't a general permission.
Advertisers are mostly businesses, but ad creatives can show people, and political ads name candidates and funders. Treat any personal data you collect under the GDPR and the CCPA, store only what you need, and keep creatives for analysis rather than republishing them. For a wider view, see our guide on whether web scraping is legal. This is not legal advice: if ad data feeds a product, ask a lawyer about your case.
Why Scrape.ly for Meta ad research
- Commercial ads outside the EU. Meta's Ad Library API covers "Ads about social issues, election or politics that were delivered anywhere in the world during the past 7 years" and "Ads of any type that were delivered to the United Kingdom (UK) or European Union during the past year." Its own parameter notes say ads that did not reach the EU "will only return if they are about social issues, elections or politics." Nike's US shopping ads from our run fall outside that; the public library shows them, and so does the Actor.
- No identity check or app. The API's first step is to confirm your identity and location at Facebook.com/ID, which "can take a few days," then create a Meta for Developers account and an app. The Actor needs a Scrape.ly token.
- Fractions of a cent. $0.05 per 1,000 ads in fees, and our 10-ad run cost $0.0015 all in.
- Built for monitoring. Schedule a daily run per competitor with
scrapePageAds.period: "last24h", and send new ads to Slack, email or Google Sheets with automations. For the bigger picture across platforms, see our guide to social media scraping.
FAQ
Is there an official Facebook Ads Library API?
Yes, Meta offers the Ad Library API, but it covers ads about social issues, elections or politics worldwide and ads of any type delivered to the UK or EU, and it requires identity confirmation and a developer app. For commercial ads in other countries, scrape the public library.
Can I scrape Facebook ads by keyword?
Yes. Search the Ad Library in your browser with a keyword, country and filters, copy the link, and paste it into urls. The Actor keeps the filters in the link, as in the German shoe-ads preset.
How many ads can I scrape per brand?
Facebook shows logged-out visitors about 30 ads per page or search. To collect more for one brand, add several URLs that split the results, for example one per country or one per media type, and set limitPerSource.
Can I see how much a competitor spends on Facebook ads?
Only for ads about social issues, elections or politics, where Meta publishes spend ranges. For commercial ads, the library does not show spend; how long an ad stays active and how many variants a brand runs are the practical signals.
Can I download the images and videos?
Every row lists the creative's image and video URLs inside snapshot. They are signed links that expire, so download the files you want to keep soon after the run.
Do I need a Facebook account?
No. The Actor reads the public Ad Library without logging in, on its built-in datacenter proxy. You need only a Scrape.ly account; the Free plan includes $5 of monthly credit.




