Meta Ad Library Scraper with EU Reach & Creative Analysis
Pricing
from $0.35 / 1,000 ad scrapeds
Meta Ad Library Scraper with EU Reach & Creative Analysis
Scrape active and inactive Facebook & Instagram ads from the Meta Ad Library by keyword, page or URL, with EU reach and audience breakdown, landing pages, video transcripts, AI creative analysis and run-to-run monitoring. Pay per result.
Pricing
from $0.35 / 1,000 ad scrapeds
Rating
0.0
(0)
Developer
Maxence Bernerd
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Meta Ad Library Scraper extracts active and inactive Facebook & Instagram ads from the Meta Ad Library by keyword, advertiser page or Ad Library URL: ad texts, titles, CTA, cleaned landing URL, image and video URLs, running time, number of variants, plus the EU and UK transparency data (total reach, reach by country, age and gender, targeted audience, beneficiary and payer) and the advertiser profile. Optional add-ons turn it into a creative-intelligence tool: landing page capture, video transcripts with the 3-second hook, AI creative analysis (hook type, angle, promise, offer, target, tone, longevity score, variant ideas) and a monitoring mode that reports what changed since the last run. Pay only for what you get: $0.35 per 1,000 ads, no subscription.
What data does Meta Ad Library Scraper extract?
One dataset row per ad, flat enough for CSV and complete enough for AI agents:
| Field | Description |
|---|---|
adArchiveId, adLibraryUrl | Stable Meta identifier and direct link to the ad in the Ad Library |
pageId, pageName, pageUrl, pageAdLibraryUrl, pageLikes, pageCategories | Advertiser page and a link to all its ads |
isActive, startDate, endDate, daysRunning | Delivery status and dates (for active ads endDate is the last day seen); daysRunning is the public proxy for a winning ad |
platforms, publisherPlatforms | facebook, instagram, audience_network, messenger, threads, whatsapp |
displayFormat | IMAGE, VIDEO, CAROUSEL, DPA / DCO (dynamic catalog ads) |
adCreativeBodies, adCreativeLinkTitles, linkDescriptions, linkCaptions | Every text variant of the creative (catalog placeholders removed) |
ctaType, ctaText | Call to action (SHOP_NOW, "Shop now") |
landingUrl, landingUrlRaw, landingDomain, utmParameters | Destination URL with tracking parameters stripped, the original URL, and the UTM parameters as an object |
imageUrls, videoUrls, videoSdUrls, videoPreviewUrls | Direct media URLs (full-size images, HD and SD mp4 videos, video thumbnails) |
collationId, collationCount | Number of variants Meta groups under the same creative |
euTransparency | totalReach, reachByCountry, reachByAge, reachByGender, targeted locations, ageMin/ageMax, gender, and the full country × age × gender breakdown (null when Meta publishes nothing) |
euBeneficiary, euPayer | Who benefits from and who pays for the ad (EU disclosure) |
ukTransparency | Same structure for ads shown in the United Kingdom |
advertiser | Page category, verification, likes, Instagram username and followers, about text |
landingPage | Final URL, status, title, H1, meta description, visible prices, screenshot URL (with includeLandingPage) |
transcript | Full text, language, duration, word timestamps and the spoken hook of the first 3 seconds (with transcribeVideos) |
creativeAnalysis | AI analysis of the creative (with enableCreativeAnalysis), see below |
categories, disclaimers, spend, currency, impressions | Only populated by Meta for regulated ads (political, housing, employment, financial) |
query, scrapedAt | Which input produced the row, and when |
In monitoring mode, one extra row per query with rowType: "diff-report" describes the changes since the previous run.
No personal data is collected: everything comes from the public Ad Library, without logging in.
How to scrape the Meta Ad Library
- Open the Actor and enter keywords (
running shoes), advertiser pages (a page ID, a handle such asnike, or a Facebook page URL) and/or Ad Library URLs copied from your browser with your own filters. - Set the countries (
ALLby default), the ad status (active, inactive or both), the media type, the platforms, the dates and Max ads per query (default 100). - Keep EU / UK transparency data on to get reach and audience for every ad Meta discloses it for. Optionally enable landing pages, video transcripts, AI creative analysis and monitoring mode.
- Click Start. Ads appear in the Output tab while the run progresses; download them as JSON, CSV, Excel or XML, or read them through the API. The Winners view lists the ads running for 30 days or more.
The Actor handles Meta's bot challenge, pagination, de-duplication, retries and session rotation on its own. Residential proxies (Apify Proxy) are on by default because the Ad Library challenges datacenter IPs.
Input examples
Every active ad of three competitors, all countries, with EU reach:
{"pageIds": ["nike", "adidas", "https://www.facebook.com/courirfr"],"countries": ["ALL"],"activeStatus": "active","maxAdsPerQuery": 500,"includeEuTransparency": true}
Video ads for a keyword in the US and the UK, transcribed and analyzed:
{"searchQueries": ["protein powder"],"countries": ["US", "GB"],"mediaType": "video","maxAdsPerQuery": 100,"transcribeVideos": true,"enableCreativeAnalysis": true}
An Ad Library URL copied from the browser (its filters take precedence), with landing pages:
{"adLibraryUrls": ["https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=FR&q=sneakers&media_type=image"],"includeLandingPage": true}
Output example
{"rowType": "ad","adArchiveId": "1036232222160843","adLibraryUrl": "https://www.facebook.com/ads/library/?id=1036232222160843","query": "page Courir (130297643710603)","pageId": "130297643710603","pageName": "Courir","pageUrl": "https://facebook.com/courirfr","pageLikes": 619289,"pageCategories": ["Shoes"],"isActive": true,"startDate": "2026-06-25","endDate": "2026-09-29","daysRunning": 96,"platforms": ["facebook", "instagram", "audience_network", "messenger", "threads"],"displayFormat": "DPA","adCreativeBodies": ["L’été en ville avec Courir 👟, sneakers aux pieds du bleu glacé Gel-NYC au jaune Moon Shoe. Dispo sur courir.com"],"adCreativeLinkTitles": ["Courir"],"linkDescriptions": ["€75", "€45", "€120"],"ctaType": "SHOP_NOW","ctaText": "Shop now","landingUrl": "https://www.courir.com/fr/c/chaussures/","landingDomain": "courir.com","utmParameters": null,"imageUrls": ["https://scontent.xx.fbcdn.net/v/t39.35426-6/730109306_....jpg"],"videoUrls": ["https://video.xx.fbcdn.net/o1/v/t2/f2/m366/AQNlhD782G....mp4"],"videoPreviewUrls": ["https://scontent.xx.fbcdn.net/v/t39.35426-6/730491380_....jpg"],"collationCount": 1,"euTransparency": {"totalReach": 3422646,"ageMin": 18,"ageMax": 65,"gender": "All","locations": [{ "name": "France", "type": "countries", "excluded": false },{ "name": "Luxembourg", "type": "countries", "excluded": false }],"reachByCountry": [{ "country": "FR", "reach": 3313879 },{ "country": "LU", "reach": 4553 }],"reachByAge": [{ "ageRange": "18-24", "reach": 368623 },{ "ageRange": "25-34", "reach": 1104419 },{ "ageRange": "35-44", "reach": 1066118 }],"reachByGender": { "male": 1385632, "female": 1888765, "unknown": 44035 },"breakdown": [{"country": "FR","ageGender": [{ "ageRange": "25-34", "male": 452118, "female": 640976, "unknown": 11325 }]}]},"euBeneficiary": "Courir France","euPayer": "Courir France","ukTransparency": null,"advertiser": {"name": "Courir","alias": "courirfr","category": "Footwear store","likes": 619289,"verification": "BLUE_VERIFIED","igUsername": "courir","igFollowers": 1030022,"igVerified": true},"scrapedAt": "2026-09-29T14:31:02.271Z"}
How much does it cost to scrape the Meta Ad Library?
Pricing is pay-per-event: you are charged only for results actually stored in your dataset. Platform usage (compute, proxies) is included.
| Event | Price | When it is charged |
|---|---|---|
| Actor start | $0.00005 | once per run |
ad-scraped | $0.00035 ($0.35 per 1,000) | per ad row |
eu-transparency-enriched | $0.0002 ($0.20 per 1,000) | per ad for which Meta actually returned EU or UK transparency data |
landing-page-captured | $0.003 | per distinct landing page captured (title, H1, prices, screenshot) |
video-transcribed | $0.01 | per video transcribed (full transcript, word timestamps, 3-second hook) |
creative-analyzed | $0.02 | per ad analyzed by AI |
monitor-diff | $0.05 | per run that produced a diff report (the first, baseline run is free) |
Examples:
| Ads | Scraping + EU data (30 % of ads) | + creative analysis | + transcripts (40 % videos) | Weekly monitoring of 5 pages × 100 ads |
|---|---|---|---|---|
| 100 | $0.04 | $2.04 | $2.44 | $0.25 per week |
| 1,000 | $0.41 | $20.41 | $24.41 | — |
| 10,000 | $4.10 | $204.10 | $244.10 | — |
Ads that Meta does not disclose EU data for, failed captures, failed transcriptions and failed AI calls are never charged. Set Maximum cost per run in the run options to cap spending: the Actor stops cleanly when the cap is reached and says so in the log.
AI creative analysis
Enable Analyze creatives with AI to add a creativeAnalysis object to every ad. The model (Claude Haiku) reads the ad texts, title, CTA, landing page title and the video transcript when available; the longevity score is computed from the running time, not by the model. A real example on a video ad that has been running for 169 days:
{"adCreativeBodies": ["The Federal Reserve Bank of Philadelphia ran a study in 2018 on lottery winners. What they found was wild...\n\nFor every $1,000 in lottery winnings someone in a neighbourhood won... the bankruptcy rate of their NEIGHBOURS went up by 2.4%.\n\nNot the winners. The neighbours."],"daysRunning": 169,"creativeAnalysis": {"hookType": "number","hookText": "The Federal Reserve Bank of Philadelphia ran a study in 2018 on lottery winners. What they found was wild...","angle": "wealth psychology, breaking the comparison trap","mainPromise": "Learn how comparing yourself to others' financial wins can sabotage your own money decisions and break the cycle of financial stress.","offer": "none","offerText": null,"cta": "Visit Instagram profile","likelyTarget": "people struggling with money, aspiring entrepreneurs, social comparison victims","tone": "eye-opening, cautionary","longevityScore": 98,"variantSuggestions": ["Open with the immediate consequence: 'Your neighbor won money and you went broke—here's the psychology behind it'","Reframe as an opportunity: 'The neighbors who stayed broke had one thing in common—discover what they missed'","Make it personal and urgent: 'Every time someone around you succeeds, you're statistically at greater risk—here's how to fix that'"],"model": "claude-haiku-4-5"}}
hookType is one of question, number, before_after, testimonial, problem_solution, other; offer is one of discount, free_trial, free_shipping, bundle, none. Ads are processed in batches of 10, in their original language.
Video transcripts
Enable Transcribe video ads to add a transcript object to every video ad: the full text, the detected language, the duration, word-level timestamps and hook, the words spoken in the first 3 seconds. Music-only videos yield an empty transcript and are not charged. Transcripts feed the creative analysis when both options are on.
Monitoring mode: what changed since last week?
Enable Monitoring mode and schedule the run. Each query keeps a snapshot in a named key-value store (meta-ad-library-monitor); from the second run on, the Actor adds a diff-report row per query and stores it as DIFF-<queryKey> in the run's key-value store:
{"rowType": "diff-report","query": "page Courir (130297643710603)","previousRunAt": "2026-09-22T06:00:12.000Z","currentRunAt": "2026-09-29T06:00:09.000Z","previousAdCount": 118,"currentAdCount": 124,"newAds": [{"adArchiveId": "1036232222160843","adLibraryUrl": "https://www.facebook.com/ads/library/?id=1036232222160843","pageName": "Courir","startDate": "2026-09-25","daysRunning": 4,"text": "L’été en ville avec Courir 👟..."}],"stoppedAds": [{"adArchiveId": "951438140810658","adLibraryUrl": "https://www.facebook.com/ads/library/?id=951438140810658","pageName": "Courir","startDate": "2026-06-25","daysRunning": 90,"text": "Jusqu'à -30% sur une sélection Courir."}],"winners": [{"adArchiveId": "2003475120600590","adLibraryUrl": "https://www.facebook.com/ads/library/?id=2003475120600590","pageName": "Courir","startDate": "2026-02-19","daysRunning": 222,"text": "Exclusivité Courir : découvrez les nouvelles collections adidas Originals dès aujourd'hui ! 🔥"}],"changedCreatives": [],"summary": "page Courir (130297643710603): 124 ads now vs 118 on 2026-09-22 — 9 new, 3 stopped, 41 running 30+ days, 0 changed creative."}
newAds are ads not seen in the previous run, stoppedAds those that became inactive or disappeared (only when the result set was not capped by maxAdsPerQuery), winners the ads running for 30 days or more, changedCreatives the ads whose copy, CTA, landing URL or media changed. Dynamic catalog ads rotate their products on every load; their images and titles are ignored on purpose.
Watch 5 competitors every Monday and post the diff to Slack
- Create a Task from the Actor with
pageIdsset to the 5 competitor pages,activeStatus: "active",maxAdsPerQuery: 300,monitoringMode: true. - In the task's Schedules tab, add a schedule:
0 7 * * 1(every Monday at 07:00). - In the task's Integrations tab, add the Slack integration (or a generic Webhook on the
ACTOR.RUN.SUCCEEDEDevent pointing to your Make, n8n or Zapier scenario). The payload contains the run and dataset IDs; thediff-reportrows are read with the dataset API, filtered onrowType = diff-report, and thesummaryfield is ready to post as is.
The first run stores the baseline for free; every following Monday costs 5 × 300 × $0.00035 + $0.05 ≈ $0.58.
How does it compare?
Facts as published on Apify Store on 29 September 2026 (prices for the free plan):
| This Actor | memo23 / facebook-ads-library-scraper-ppe | jmlp / meta-ad-library-scraper | azzouzana / meta-facebook-instagram-ads-library | curious_coder / facebook-ads-library-scraper | |
|---|---|---|---|---|---|
| Price per 1,000 ads | $0.35 | $0.50 + $0.05 per run | $0.15 + platform usage billed to you (≈ $0.25) | $0.50 (+ $0.50 with details) | $0.75 |
| Keywords, pages, URLs as input | yes | yes | yes | URL only | URL only |
| EU reach, audience, payer | yes, +$0.20 per 1,000 when present | yes | no | yes, +$0.50 per 1,000 | yes |
| UK transparency, advertiser profile | yes | no | no | partial | yes (UK) |
| Cleaned landing URL + UTM, landing page capture | yes, capture $0.003 | link only | link only | link only | link only |
| Video transcript with hook | $0.01 per video | ≈ $0.05 per video | no | no | no |
| AI creative analysis | $0.02 per ad | no | no | no | no |
| Diff between runs | $0.05 per run | new-ads-only filter | no | no | no |
| Flat, null-filled output schema with views | yes | raw Meta JSON | yes | raw Meta JSON | raw Meta JSON |
Use cases
- Competitive intelligence — pull every active ad of your competitors, sort by
daysRunning, read the winners' hooks and offers. - Creative research for UGC creators and agencies — filter video ads by keyword, transcribe them and get the hook, angle and CTA of the top performers in one table.
- Weekly monitoring — schedule the monitoring mode on your clients' competitors and receive the new, stopped and long-running ads in Slack.
- EU market sizing — reach by country, age and gender for any advertiser active in Europe, data that the Ad Library shows but the official API restricts.
- Data for AI agents — clean JSON with stable IDs, ready for RAG pipelines or agents through the Apify MCP server.
Using the Actor from code
Run it and read the results with the Apify API:
curl -X POST "https://api.apify.com/v2/acts/maxencebernerd~meta-ad-library-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \-H "Content-Type: application/json" \-d '{"searchQueries": ["gymshark"], "countries": ["ALL"], "maxAdsPerQuery": 50}'
JavaScript (npm install apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('maxencebernerd/meta-ad-library-scraper').call({pageIds: ['nike', 'adidas'],countries: ['ALL'],maxAdsPerQuery: 200,enableCreativeAnalysis: true,});const { items } = await client.dataset(run.defaultDatasetId).listItems();const winners = items.filter((ad) => ad.rowType === 'ad' && ad.daysRunning >= 30);console.log(winners.map((ad) => [ad.pageName, ad.daysRunning, ad.creativeAnalysis?.hookType]));
Python (pip install apify-client):
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("maxencebernerd/meta-ad-library-scraper").call(run_input={"searchQueries": ["protein powder"],"countries": ["US", "GB"],"mediaType": "video","transcribeVideos": True,})for row in client.dataset(run["defaultDatasetId"]).iterate_items():if row["rowType"] == "ad" and row.get("transcript"):print(row["pageName"], row["daysRunning"], "days |", row["transcript"]["hook"])
MCP: use it from Claude, Cursor or any AI agent
The Actor is exposed through the Apify MCP server. Add it to your MCP client (example for Claude Desktop):
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=maxencebernerd/meta-ad-library-scraper","headers": { "Authorization": "Bearer <YOUR_APIFY_TOKEN>" }}}}
Then ask your agent: "Find the 50 longest-running Gymshark ads in the EU and summarize their hooks and offers." The agent calls the Actor, waits for the dataset and reads the rows.
Integrations
Every run can trigger Slack, Zapier, Make, n8n, Google Sheets, Google Drive, Airbyte, webhooks or any other Apify integration. The dataset is also readable through the LangChain and LlamaIndex Apify loaders. Schedule the Actor from the Schedules tab for continuous monitoring.
FAQ
How is this different from the official Ad Library API? Outside the EU and the UK, the official API only returns political and social-issue ads, requires an identity-verified Facebook account and an app, and does not give media URLs, CTA or page likes. This Actor reads the public Ad Library interface, the same pages anyone can open without logging in, and returns commercial ads from every country with their creatives, plus the EU/UK transparency data.
Is it legal to scrape the Ad Library? The Ad Library is a public transparency repository that Meta must publish under the EU Digital Services Act, consultable without an account. The Actor collects only what the Library shows to a logged-out visitor, never logs in and collects no personal data of users. Ad creatives remain the property of their advertisers: the Actor returns their URLs and does not re-host media. You remain responsible for how you use the data. Read Apify's legal guide to web scraping.
Why do some ads have no EU data?
Meta publishes EU transparency only for ads that reached the EU, and even then not for all of them (in our tests, 30 % to 55 % of a French retailer's ads carried it). UK ads carry ukTransparency without beneficiary and payer. Ads restricted to other countries never have it; the Actor skips the extra call and the charge for those.
Are inactive and removed ads available?
Inactive ads are available for one year when they reached the EU or the UK (choose inactive or all). Commercial ads shown only elsewhere disappear from the Library when they stop, and ads removed by Meta are not returned. spend and impressions exist only for regulated ads.
How fresh is the data?
Every run fetches live data at the time it runs; endDate of an active ad is the last day Meta saw it. Media URLs are signed by Meta's CDN and expire after a few days: download what you need promptly.
What if Meta blocks the run?
The Ad Library answers empty results to IPs that query too fast. The Actor paces its requests, rotates residential sessions, changes IP during long queries and retries each query up to three times; a query that still returns nothing is reported as empty and never charged. Failed queries are listed in the FAILED-SOURCES record of the key-value store.
Can I request a feature or report a problem? Use the Issues tab of the Actor. Custom extractions and integrations are available on request.