Skip to content

How to Scrape the Facebook Ads Library (Meta Ad Library)

Scrape the Facebook Ads Library for any brand, page or keyword: ad copy, creatives, call to action, landing page, start date, platforms and the Ad Library link. A real run on Nike's active US ads, its exact cost, and code for curl, Python, Node.js and AI agents.

Published
Reading time
9 min read
Pixel-art robot with an orange >_ on its terminal head pulls an ad card with an image and a blue button out of a monitor showing the blue Facebook logo above two more ad cards, and drops it into a crate
In this article
  1. What data you can get from the Meta Ad Library
  2. How to scrape the Facebook Ads Library without code
  3. Scrape the Facebook Ads Library with the API
  4. A real run: Nike's active US ads
  5. What it costs
  6. What to watch out for
  7. Is it legal to scrape the Facebook Ads Library?
  8. Why Scrape.ly for Meta ad research
  9. FAQ
  10. Is there an official Facebook Ads Library API?
  11. Can I scrape Facebook ads by keyword?
  12. How many ads can I scrape per brand?
  13. Can I see how much a competitor spends on Facebook ads?
  14. Can I download the images and videos?
  15. Do I need a Facebook account?

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

  1. Open the Facebook Ad Library Scraper in the Scrape.ly Store.
  2. 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.
  3. Swap in the brand you're researching. This is the exact input of our run:
json
{
  "urls": [{ "url": "https://www.facebook.com/nike" }],
  "count": 10,
  "scrapePageAds.activeStatus": "active",
  "scrapePageAds.countryCode": "US",
  "scrapePageAds.sortBy": "impressions_desc"
}
  1. Click Start. Ten ads take a few seconds.
  2. 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. limitPerSource caps each URL.
  • scrapePageAds.activeStatus, scrapePageAds.countryCode, scrapePageAds.sortBy, scrapePageAds.period: filters for page URLs: active/inactive/all, a two-letter country or ALL, impressions_desc or most_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.

shell
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:

python
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):

javascript
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:

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. pageInfo reported "NIKE, Inc. is responsible for this Page," a page created on 21 May 2008, and the page currently running ads; snapshot.page_like_count was 39,497,958.
  • No spend or reach. As expected for commercial ads in the US, spend and reach_estimate were empty.

The run's log, without the platform's start-up lines:

Text
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=false

2.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. scrapeAdDetails adds 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 from snapshot.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.

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.

  • facebook ads
  • meta ad library
  • competitor research
  • advertising
  • python
  • api

About the author

Actor publisher on the Scrape.ly Store

Posts, reels, comments and creator stats, from TikTok and YouTube to Weibo and Bluesky. For social listening, creator research and catching a trend while it is still small. A Scrapely studio.

//Keep reading\\

The internet is full of data.
Start owning yours.

Scrape.ly gives you the infrastructure, the tooling, and the team to extract, process, and operationalize web data at any scale. Setup takes minutes. The advantage lasts forever.

No credit card. No setup calls.