Facebook Ads & Ad Library Scraper API
Our Facebook ads scraper reads the public Meta Ad Library and returns an advertiser's ads as structured JSON: the creative body, the ad snapshot URL, the start and end dates, the platforms each ad ran on, and the spend and impression ranges Meta discloses for political and issue ads. Pass a page id, a page name, a keyword, or a full Ad Library URL.
Getting Facebook Ads & Ad Library data is harder than it looks
The Meta Ad Library is public, but the page is a React app that loads its ad rows from an internal GraphQL call guarded by a per-load lsd token, so a plain request returns an empty shell. The official Ad Library API only covers ads about social issues, elections, or politics and needs an approved access token, so commercial ads from a brand like Nike are not returned there at all.
Hit the Facebook Ads & Ad Library Scraper API with one request
curl "https://api.facebookscraperapi.com/api/v1/facebook/ads?page_id=15087023444&country=US&api_key=$API_KEY" import requests
BASE = "https://api.facebookscraperapi.com"
API_KEY = "YOUR_API_KEY"
# Pass a numeric page_id, a page vanity, a keyword (q), or a full ads/library URL.
data = requests.get(
f"{BASE}/api/v1/facebook/ads",
params={
"page_id": "15087023444", # Nike
"country": "US",
"active_status": "all",
"limit": 30,
"api_key": API_KEY,
},
timeout=30,
).json()
print(data["results_count"], "ads for", data["query"])
for ad in data["ads"]:
print(ad["ad_archive_id"], ad["is_active"], ad["cta_text"])
print(" ", ad["ad_creative_body"])
print(" ", ad["ad_snapshot_url"])
print(" ran:", ad["start_date_iso"], "->", ad["end_date_iso"]) Parameters
| Parameter | Required | Default | Notes |
|---|---|---|---|
page_id | optional | - | Numeric advertiser Page id (the Ad Library view_all_page_id). One of page_id, page, q, or url is required. |
page | optional | - | Advertiser Page vanity or username. Resolved to a numeric page id via one lookup hop before the ad search. |
q | optional | - | Free-text keyword to search ads across all advertisers instead of a single page. |
url | optional | - | A full facebook.com/ads/library/ URL. The view_all_page_id, q, country, and active_status are parsed out of it. |
country | optional | US | ISO country code the Ad Library is scoped to, or ALL. Defaults to US. |
active_status | optional | all | Filter by delivery status: active, inactive, or all. Defaults to all. |
ad_type | optional | all | The Ad Library ad_type facet, e.g. all or political_and_issue_ads. Defaults to all. |
limit | optional | 30 | Maximum ads to return, 1 to 100. One Ad Library page is about 30. Defaults to 30. |
api_key | required | - | Your API key, passed as a query parameter. Get one free at signup. |
The Facebook Ads & Ad Library Scraper API output schema
{
"query": "15087023444",
"page_id": "15087023444",
"country": "US",
"active_status": "all",
"results_count": 30,
"total_results": 30,
"source": "embedded",
"ads": [
{
"ad_archive_id": "1520310666349109",
"page_id": "15087023444",
"page_name": "Nike",
"ad_creative_body": "Add a retro touch to any fit.",
"ad_creative_link_title": "Find Nike Near You",
"ad_creative_link_url": "https://www.nike.com/w/womens-summer-essentials-lifestyle-13jrmz5e1x6z6pei9",
"ad_snapshot_url": "https://www.facebook.com/ads/library/?id=1520310666349109",
"start_date": 1777446000,
"start_date_iso": "2026-04-29T07:00:00.000Z",
"end_date": 1779692400,
"end_date_iso": "2026-05-25T07:00:00.000Z",
"is_active": false,
"platforms": ["FACEBOOK", "INSTAGRAM"],
"impressions": { "impressions_text": null, "impressions_index": -1 },
"spend": null,
"currency": null,
"cta_text": "Shop now",
"cta_type": "SHOP_NOW",
"display_format": "IMAGE",
"page_profile_uri": "https://www.facebook.com/nike/",
"page_like_count": 39600590,
"collation_count": 3,
"images": [
"https://scontent-tpe1-1.xx.fbcdn.net/v/t39.35426-6/680632406_1648649816184681_5171813441674285678_n.jpg"
]
},
{
"ad_archive_id": "1181819485586009",
"page_id": "15087023444",
"page_name": "Nike",
"ad_creative_body": "Black women are rarely recognized for the hard work they put in. Join us in celebrating their hard work and help level the playing field. #WePlayReal",
"ad_creative_link_title": null,
"ad_creative_link_url": "https://www.nike.com/",
"ad_snapshot_url": "https://www.facebook.com/ads/library/?id=1181819485586009",
"start_date": 1615190400,
"start_date_iso": "2021-03-08T08:00:00.000Z",
"end_date": 1619766000,
"end_date_iso": "2021-04-30T07:00:00.000Z",
"is_active": false,
"platforms": ["INSTAGRAM"],
"impressions": { "impressions_text": ">1M", "impressions_index": 39 },
"spend": "$40K - $45K",
"currency": "USD",
"cta_text": "Learn more",
"cta_type": "LEARN_MORE",
"display_format": "VIDEO",
"page_profile_uri": "https://www.facebook.com/nike/",
"page_like_count": 39600590,
"collation_count": 28,
"images": null
}
]
} | Field | Type | Description |
|---|---|---|
query | string | The keyword or page id the search was run for. |
page_id | string | The numeric advertiser Page id resolved for the search, or null for a keyword search. |
source | string | Where the ads came from: graphql when the paginated call succeeded, embedded when parsed from the first page render. |
results_count | integer | Number of ads returned in the ads array. |
ads | array | The ads. Each item carries the fields below. |
ad_archive_id | string | The Ad Library archive id, the stable identifier for the ad. |
page_name | string | The advertiser Page name, e.g. Nike. |
ad_creative_body | string | The ad's primary text or caption. |
ad_creative_link_title | string | The headline shown on the ad card, or null when the creative has none. |
ad_creative_link_url | string | The landing URL the ad links to. |
ad_snapshot_url | string | The public Ad Library permalink to view this exact ad. |
start_date / end_date | integer | The ad's run window as unix seconds. start_date_iso and end_date_iso give the same values as ISO strings. |
is_active | boolean | Whether the ad was still delivering at capture time. |
platforms | array | The publisher platforms the ad ran on, e.g. FACEBOOK, INSTAGRAM, AUDIENCE_NETWORK, MESSENGER. |
impressions | object | Impression range Meta discloses (impressions_text like >1M), populated only for political and issue ads; null otherwise. |
spend | string | Spend range Meta discloses (e.g. $40K - $45K) for political and issue ads; null for commercial ads. |
cta_text / cta_type | string | The call-to-action label and type, e.g. Shop now / SHOP_NOW. |
display_format | string | The creative format, e.g. IMAGE, VIDEO, DPA, or DCO. |
page_like_count | integer | The advertiser Page's like count at capture time. |
collation_count | integer | How many near-identical variants Meta grouped with this ad, or null. |
images | array | Creative image URLs when the ad snapshot exposes them, or null for video and dynamic formats. |
Build with Facebook data
Competitor ad monitoring
Creative and hook research
Ad longevity signals
Political and issue ad transparency
Platform mix analysis
Ad creative archives
Why teams ship on our Facebook Ads & Ad Library Scraper API
We do the multi-hop work the Ad Library forces on you: minting the per-load lsd token, reading the ads embedded in the first render, and following the internal GraphQL pagination for the full set, all from a US residential exit. You pass a page id, vanity, keyword, or Ad Library URL and get flat, validated JSON back in about 2.6 seconds, with no token to manage and no political-only access gate.
Page, keyword, or URL input
Commercial ads included
Token and GraphQL handled
Anti-bot and residential routing
Country scoping
Honest disclosure fields
How the Facebook Ads & Ad Library Scraper API compares
| Our API | DIY (requests / headless) | Official Ad Library API | |
|---|---|---|---|
| Commercial (non-political) ads | Yes, any advertiser | Possible but you fight the token and GraphQL | No, issue, election, and political ads only |
| Access | One API key | You mint the lsd token per load | Approved access token plus identity confirmation |
| Setup | API key only | Residential proxies, headless browser, parsers | Meta developer app and Ad Library API access |
| Anti-bot and proxies | Built in, US residential | You build and maintain it | Not applicable |
| Output | Flat, validated JSON | Whatever you parse from GraphQL | JSON you map yourself, limited fields |
| Spend and impressions | Returned where Meta discloses them | You parse them yourself | Returned for political and issue ads |
Pricing built for scale
| Plan | Price | Best for |
|---|---|---|
| Free | 1,000 requests | Testing and small jobs |
| Pro | $0.60 / 1k | Production workloads |
| Pay-as-you-go | $0.90 / 1k | Spiky or one-off volume |
Median response 2.6s. You only pay for successful requests.
FAQ
A Facebook ads scraper is a tool that reads the public Meta Ad Library and returns an advertiser's ads as structured data. Our Facebook ads scraper API takes a page id, page vanity, keyword, or Ad Library URL and returns each ad's creative body, headline, snapshot URL, run dates, platforms, call-to-action, display format, and the spend and impression ranges Meta discloses for political and issue ads, all as JSON from one request.
Any advertiser. The Meta Ad Library shows every active and recent ad for any Page, which is why our sample returns 30 commercial ads for Nike. The distinction only affects the disclosure fields: Meta publishes spend and impression ranges for ads about social issues, elections, or politics, so those come back populated, while commercial ads return null spend and impressions because Meta does not disclose them.
No. You authenticate with a single facebookscraperapi key. The official Ad Library API only covers issue, election, and political ads and requires an approved access token plus identity confirmation, so it cannot return a brand's commercial product ads. Our endpoint reads the public Ad Library that anyone can view in a browser and returns the ads as JSON.
You do not have to. Pass the Page vanity as the page parameter, or a keyword as q, and we resolve the numeric advertiser id for you before searching. If you already have a full ads/library URL with a view_all_page_id, pass it as the url parameter and we parse the id out of it.
For political and issue ads, yes: Meta discloses a spend range like $40K to $45K and an impression range like greater than 1M, and we return them in the spend and impressions fields. For ordinary commercial ads Meta does not publish those figures, so both come back null rather than estimated. This keeps the data honest to what the Ad Library actually shows.
One Ad Library page is roughly 30 ads, and the limit parameter accepts 1 to 100. We read the ads embedded in the first render and, when the internal pagination call succeeds, follow it for the full set, then de-duplicate by ad_archive_id. The response includes a source field so you can see whether the ads came from the GraphQL pagination or the embedded first page.
Median end-to-end response is about 2.6 seconds, which includes US residential routing, minting the lsd token, reading the embedded ads, and the pagination hop. You are billed only for successful requests, and the free tier includes 1,000 requests to test against real advertisers first.