Facebook Ads Library Scraper — Meta & Instagram Ads + EU Reach
Pricing
from $0.60 / 1,000 results
Facebook Ads Library Scraper — Meta & Instagram Ads + EU Reach
Scrape the Facebook Ads Library (Meta Ad Library): Facebook, Instagram, Messenger & Threads ads with copy, images, videos, CTAs, landing URLs. Optional EU reach by age, gender & country plus targeting. Search by URL, keyword, Page ID or ad ID. MCP-ready for AI agents.
Pricing
from $0.60 / 1,000 results
Rating
5.0
(1)
Developer
AffiliateScope
Maintained by CommunityActor stats
4
Bookmarked
220
Total users
10
Monthly active users
16 days ago
Last modified
Categories
Features
Share
Facebook Ads Library Scraper (Meta Ad Library)
Export Facebook and Instagram ads from the Facebook Ads Library (Meta Ad Library) as structured JSON: copy, creatives, CTAs, landing URLs and, optionally, EU reach and targeting for each ad.
Paste any Ad Library URL, or search by keyword, Facebook Page ID or ad ID. Covers Facebook, Instagram, Messenger, Threads and Audience Network. No login. No Meta developer account. Pay per ad, plus a small per-run fee — see Pricing.
Built for AI agents and scheduled pipelines: competitor monitoring, creative research and affiliate offer tracking — and run in our own production pipelines before it reaches the Store.
Jump to: Use it from an AI agent (MCP) · Ready-made tasks · Console & API · Output · Pricing
Use it from an AI agent (MCP)
Give Claude, ChatGPT, Cursor, VS Code or any MCP client direct access to Meta's Ad Library. Add the Apify MCP server with only this Actor as a tool:
{"mcpServers": {"meta-ad-library": {"url": "https://mcp.apify.com?tools=affiliatescope/meta-ads-scraper"}}}
On first connect your browser opens to sign in to Apify (OAuth) — no token in the config. Prefer a token? Add "headers": { "Authorization": "Bearer <APIFY_TOKEN>" }. Client-specific setup: mcp.apify.com.
Then just ask:
- "Pull every active ad Gymshark runs in the US and summarize the hooks and offers they're testing."
- "Which brands are advertising promo codes on Instagram this week? Give me the landing URLs."
- "For running-shoe ads in Germany, who reaches the most people, and which age group?" — the agent turns on ad details for EU reach.
- "Compare lululemon's ads in the US, UK and Germany — what's localized?"
Why it works well for agents:
- Typed, documented output — every field is described in the dataset schema, so the agent knows what
spend,ad_detailsor__metadata.sourceTypemean without guessing. - Hard caps —
maxAdsPerSource,maxAdsand your run budget stop a run exactly where you set them, so an agent can't run up a surprise bill. - Plain-language inputs — keywords, Page IDs, countries, dates and sort match what you'd say out loud.
- Every run explains itself — the run's status message says what happened and what to do next, e.g. "Scraped 15 ads from 1 of 2 sources. Stopped early: max ads reached (15); raise maxAds to get more." Zero results come with a hint for widening the search, and failed sources name the reason. The same report is saved as the run's
OUTPUTrecord, with a per-source status, so an agent can retry just what failed.
Ready-made tasks
One-click setups for common jobs. Open one, run it as-is, then swap in your own brands, keywords or countries — or schedule it. Each task page also works as a brief an AI agent can read.
| Task | Use it to | Output view |
|---|---|---|
| Monitor competitor ads | Track every active ad from a list of brands, newest first | Overview |
| EU reach & targeting | See reach by age × gender × country and who an ad targets | EU reach |
| Video ad swipe file | Collect active video ads with HD video URLs, hooks and CTAs | Creatives |
| Promo & coupon code ads | Find brands advertising discount codes, with landing URLs | Creatives |
| Political ad spend | Export spend ranges, impressions and paid-for-by for issue ads | Spend |
| Multi-market presence | Compare one brand's ads across countries | Overview |
| Credit card offers | Track card issuers' offers for finance affiliate content | Creatives |
| Instagram fashion ads | Pull Instagram-only image ads for new collections | Creatives |
| Ad Library URL export | Paste any Ad Library search and export every matching ad | Overview |
All tasks are also listed under the Example tasks tab above.
Console & API
From the Apify Console:
- Click Try for free at the top
- In the input form, either:
- paste Ad Library URLs (Option A), or
- enter keywords, Page IDs or ad IDs plus filters (Option B)
- Click Start. Ads appear in the dataset page by page as they're scraped.
From the API (curl):
curl -X POST 'https://api.apify.com/v2/acts/affiliatescope~meta-ads-scraper/runs?token=YOUR_APIFY_TOKEN' \-H 'Content-Type: application/json' \-d '{"searchQueries": ["nike"],"countries": ["US"],"activeStatus": "ACTIVE","maxAdsPerSource": 500}'
Export as CSV, JSON, JSONL or XLSX from the Console, or read /v2/datasets/{id}/items. Add ?view=overview, creatives, euReach or spend for a ready-made column set.
What you get per ad
ad_archive_id+ a direct Ad Library link (__metadata.adLibraryUrl)- Advertiser: Page name, ID, profile picture, categories, like count, profile URL
- Creative text: body, headline, caption, link description, byline
- Images: original + resized URLs for every variant (single image, carousel, dynamic creative)
- Videos: HD + SD URLs, preview image
- CTA: button text + type (
Shop Now,Learn More,Install Now…) - Landing URL with tracking parameters kept — affiliate tags, UTMs and campaign IDs intact
- Delivery: start/end dates, active flag, platforms (Facebook, Instagram, Messenger, Threads, Audience Network)
- Political & issue ads: spend range, currency, impressions band, paid-for-by line
__metadata: where the ad came from (source, query, country, page, order, scrape time)
Optional — ad details (scrapeAdDetails), the Ad Library's "See ad details" panel, attached as ad_details:
- EU reach: total reach plus an age × gender breakdown per EU country
- Targeting: targeted locations, age range and gender
- Payer & beneficiary (EU transparency disclosures)
- Advertiser profile: about text, Instagram handle and followers, verification badge, Page likes
Meta publishes reach and targeting only for ads delivered in the EU, so for US-only ads ad_details carries the advertiser profile but no reach.
Every record is Meta's raw response, passed through untouched. When Meta adds a field, it shows up in your data without waiting for an update.
Sample output
A search result (trimmed). Records keep Meta's own field names; scrape context lives in the __metadata sidecar.
{"ad_archive_id": "638485615120135","page_id": "15087023444","page_name": "Nike","is_active": false,"start_date": 1699430400,"end_date": 1745650800,"publisher_platform": ["FACEBOOK", "INSTAGRAM", "AUDIENCE_NETWORK", "MESSENGER"],"spend": null,"impressions_with_index": { "impressions_text": null, "impressions_index": -1 },"categories": ["UNKNOWN"],"snapshot": {"body": { "text": "Encuentra tu mejor estilo. Llegó el momento de que tu siguiente favorito sea el tuyo..." },"cta_text": "Install now","cta_type": "INSTALL_MOBILE_APP","link_url": "http://play.google.com/store/apps/details?id=com.nike.omega&...","title": "{{product.name}}","page_like_count": 39643468,"cards": [{ "body": "Encuentra tu mejor estilo...", "original_image_url": "https://scontent.xx.fbcdn.net/..." }],"display_format": "DCO"},"__metadata": {"order": 1,"sourceOrder": 1,"page": 1,"sourceKey": "kw:US:nike","sourceType": "keyword","query": "nike","country": "US","adLibraryUrl": "https://www.facebook.com/ads/library/?id=638485615120135","scrapedAt": "2026-04-19T13:28:01.053Z"}}
The ad_details block from a German search with ad details on (trimmed):
"ad_details": {"aaa_info": {"payer_beneficiary_data": [{ "payer": "Follow Your Legend", "beneficiary": "Follow Your Legend" }],"targets_eu": true},"advertiser": {"page": { "about": { "text": "..." } },"ad_library_page_info": {"page_info": { "page_category": "Brand", "likes": 124092, "ig_username": "followyourlegend", "ig_followers": 406982, "page_verification": "NOT_VERIFIED" }}},"transparency_by_location": {"eu_transparency": {"eu_total_reach": 142654,"gender_audience": "All","age_audience": { "min": 18, "max": 65 },"location_audience": [{ "name": "Italy", "type": "countries", "excluded": false }, { "name": "Netherlands", "type": "countries", "excluded": false }],"age_country_gender_reach_breakdown": [{ "country": "AT", "age_gender_breakdowns": [{ "age_range": "18-24", "male": 621, "female": 91, "unknown": 81 }] }]}}}
Notes on fields:
spend,currency,impressions_with_index.impressions_textare filled for political and issue ads. Commercial ads leave them empty — Meta doesn't publish spend for them.snapshot.cards[]holds one entry per creative variant (carousels and dynamic creative have several), each with its own copy and media.snapshot.images/snapshot.videosare set for single-creative ads; multi-creative ads carry media insidesnapshot.cards[].- You also get fields not shown here (
collation_id,gated_type,regional_regulation_data,targeted_or_reached_countries…) — everything Meta sends.
Inputs
Mix any of these sources in one run:
| Source | What it does |
|---|---|
| Ad Library URLs | Paste any facebook.com/ads/library URL — every filter in it is kept (country, status, platforms, languages, dates, sort) |
| Search queries | Keyword search, one per line, run for each country you pick |
| Page IDs | Numeric Facebook Page IDs — every ad from those Pages |
| Ad IDs | Specific ad_archive_ids — one ad in, one ad out. …/ads/library/?id=… links work too |
Filters (for search queries and Page IDs; pasted URLs carry their own):
- Countries: ISO codes (
US,GB,DE…) orALLfor worldwide - Active status: active / inactive / all
- Ad category: all / political & issue / housing / employment / financial products
- Media type: all / image / video / meme / no media
- Publisher platforms: any of Facebook, Instagram, Messenger, Audience Network, Threads
- Content languages: ISO-639 codes
- Date range: from / to,
YYYY-MM-DD - Sort: impressions, high to low (default) / most recent
Output controls:
- Max ads per source — default
100;0= everything Meta has indexed - Max ads total — hard cap across all sources; the run stops as soon as it's reached
- Skip duplicate ads — on by default: an ad found by two keywords or two countries is kept once and charged once
- Add ad details — off by default; see above
Every field is documented in the Input tab.
Pricing
Pay per ad, with no subscription and no monthly minimum. Current prices for your Apify plan are on the Pricing tab of this page, and higher plans pay less per ad.
What you pay for:
- Run start: once per run at the default 512 MB memory (once per GB above that).
- Each ad in your dataset.
- Ad details (optional): only when
scrapeAdDetailsis on and Meta returns data for that ad.
What you never pay for: duplicate ads skipped by de-duplication, and ad details Meta doesn't return.
Set Max total charge (maxTotalChargeUsd) on a run and the scraper stops cleanly when the budget is reached.
Why this scraper
| Alternative | Why use this instead |
|---|---|
Meta's Ad Library API (ads_archive) | No identity verification or developer app. Covers commercial ads with full creative fields, which the official API limits mostly to political and issue ads. |
| Building it yourself | Nothing to build or maintain. When Meta changes the Ad Library, keeping the scraper working is our job, not yours. |
| Browsing the Ad Library by hand | Structured data at any volume, scheduled refresh, CSV / JSON / XLSX export, EU reach in the same run. |
What sets the output apart:
- Raw, complete records — Meta's full response, not a reduced normalized subset
- EU reach and targeting in the same run — no second tool, no second export to join
- Caps that actually stop the run — per source, in total, and at your budget
- Failures you can see — sources that fail are listed at the end of the run instead of silently returning nothing
Speed & reliability
- Throughput: about 100 ads per minute per source — a 1,000-ad keyword takes roughly 10 minutes. Sources run in parallel, so 10 keywords take about as long as one.
- With ad details expect roughly half the speed.
- Rate limits and Ad Library updates are handled automatically — no settings to tune.
- Failures: any source that still fails after retries is listed in the run summary with the reason. If every source fails, the run is marked failed.
Performance tuning
Memory
The default 512 MB handles up to about 10 parallel sources.
| Workload | Memory |
|---|---|
| 1–10 sources | 512 MB (default) |
| 10–40 sources in parallel | 1 GB |
| 40+ sources in parallel | 2 GB |
One very large source (maxAdsPerSource 100,000+) | 1 GB |
More memory doesn't make a run faster — it only raises the run-start fee, which is charged per GB. Too little ends the run with an out-of-memory error.
Concurrency (maxConcurrency)
Default 3: how many sources (URLs, keywords, Page IDs, ad IDs) run at once.
- Between sources: parallel. 10 keywords with
maxConcurrency: 10all scrape at the same time. - Within one source: one page at a time.
Concurrency is capped at the number of sources, and the run log shows the effective value (e.g. concurrency 1 (capped from 20: only 1 source)).
| You have | Set maxConcurrency to |
|---|---|
| 1 source | 1 |
| 2–5 sources | number of sources |
| 5–20 sources | 5 |
| 20+ sources, time-sensitive | 10 (and 1 GB memory) |
A 10,000-ad single keyword takes about 100 minutes. Split it into 10 keywords × 1,000 ads with maxConcurrency: 10 and it finishes in about 10.
Integration
- AI agents via the Apify MCP server — see above
- Schedules from the Apify Console (hourly, daily, weekly, cron)
- Webhooks on run completion — Zapier, Make, n8n, Slack or your own backend
- Dataset API — CSV, JSON, JSONL or XLSX, or stream over HTTP
- Warehouse exports — BigQuery, Snowflake, S3 via Apify integrations
runTag— label every record from a scheduled run so you can group snapshots later
FAQ
How do I find a Facebook Page ID?
Open the brand's ads in the Ad Library; the URL contains view_all_page_id=<number>. Or just paste that Ad Library URL into Ad Library URLs.
Why is EU reach empty for some ads?
Meta publishes reach, age/gender breakdowns and targeting only for ads delivered in the EU. Search EU countries (DE, FR, IT…) to get them. US-only ads still get the advertiser profile in ad_details.
Why are spend and impressions empty? Meta publishes them only for political and issue ads. Set Ad category to political & issue to get them.
Do date filters and sort apply to ad IDs? No. An ad ID returns that exact ad. Filters apply to keyword and Page ID sources; pasted URLs use their own filters.
What happens with duplicates? With Skip duplicate ads on (default), an ad found by several sources is kept once — first source wins — and charged once. Turn it off to keep one copy per source, for example to compare countries.
Is this legal?
The Meta Ad Library is a public transparency tool — this is the same data anyone can browse at facebook.com/ads/library, with no login. Reach and targeting in ad_details are the aggregated disclosures Meta publishes under the EU Digital Services Act; there is no data about individual users.
How fresh is the data? Each run reads Meta's live Ad Library. There's no cache in between — you get what the Ad Library shows at that moment.
Will it break when Meta changes the Ad Library? Most Ad Library changes are handled automatically. When one needs a fix, we ship it — failures are triaged the same day.
Can I run it on a schedule? Yes. Schedule a task in the Apify Console and set Max total charge for predictable monthly spend.
Support
Contact affiliatescope through the Apify Console. We reply within one business day; confirmed scraper failures are triaged the same day.
Keywords
Facebook Ads Library scraper, Facebook Ad Library scraper, Meta Ads Library scraper, Meta Ad Library API, Meta Ad Library MCP, ad data for AI agents, Facebook ads scraper, Instagram ads scraper, Facebook ad spy tool, competitor ad monitoring, creative research, EU DSA ad reach, ad targeting data, political ad transparency, Ad Library export, affiliate marketing intelligence.