Facebook & Meta Ads Library Scraper + Tracker
Pricing
from $0.60 / 1,000 baseline ad results
Facebook & Meta Ads Library Scraper + Tracker
Scrape Facebook and Meta Ads Library creatives, copy, CTAs and landing links. Track competitor ads and detect new, updated and safely ended ads.
Pricing
from $0.60 / 1,000 baseline ad results
Rating
0.0
(0)
Developer
Luka
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 hours ago
Last modified
Categories
Share
Scrape Facebook and Meta Ads Library creatives, copy, CTAs and landing links — then detect new, updated and safely ended competitor ads on the next scheduled run.
Point it at a brand, a Facebook page or a keyword. Get back the full ad copy, creatives, call-to-action, destination links and delivery dates from the Meta Ad Library. Run the same query again later and every ad comes back labelled — new, changed, unchanged, or gone.
🎯 What can this Actor do?
🔎 Search by keyword, brand, page URL or Ad Library URL — mix up to 25 targets in one run
📝 Get the actual ad copy — body text, headlines, descriptions, captions and CTA, including every card of a carousel
🖼️ Get the creatives — direct image and video URLs, without paying to download the media itself
🔗 See where the ad sends people — the destination link the advertiser attached to the ad
🌍 Filter before you scrape — country, active status, ad category, media type and date range, so you pay only for the ads you want
🔔 Track changes over time — every ad is labelled NEW, UPDATED, UNCHANGED or ENDED against your previous run, and an ENDED is only ever raised from a snapshot proven complete on both sides
✅ Know when your data is complete — every target reports whether the source was exhausted, capped or only partially read
🆚 Baseline or Changes — which one do I need?
This is the only real decision you have to make. Everything else has a sensible default.
| BASELINE | CHANGES | |
|---|---|---|
| What you get | Every matching ad in the current scan | The current scan with every row labelled NEW, UPDATED, UNCHANGED or safely proven ENDED |
| Answers | "What is my competitor advertising?" | "What did my competitor change?" |
| Best for | One-off research, creative swipe files, market scans | Daily or weekly monitoring, alerting, trend tracking |
| Needs a previous run | No | Second run onwards |
| Free-tier price | $0.02 run start + $0.70 / 1,000 delivered rows | $0.02 run start + $1.10 / 1,000 delivered monitoring rows |
Start with BASELINE. Switch to CHANGES when you want the Actor to do the comparing for you.
⬇️ Input
A one-off creative scan — a keyword and nothing else:
{"searchTerms": ["running shoes"]}
A competitor watch on two brands, tracking changes:
{"productLevel": "CHANGES","searchTerms": ["nike","adidas"],"country": "US","maxAdsPerTarget": 100}
Filtered market scan:
{"searchTerms": ["protein powder", "creatine"],"country": "GB","activeStatus": "ACTIVE","mediaType": "VIDEO","dateFrom": "2026-06-01","maxAdsPerTarget": 100}
You can paste a Meta Ad Library URL straight from your browser instead of using search terms — the Actor reads the filters out of the URL. Keyword searches and numeric-page-ID Ad Library URLs use the 256 MB default. An uncached Facebook handle such as facebook.com/nike may require the optional browser-continuity layer. That layer is deliberately disabled under the current three-event pricing and fails closed before browser work; use a numeric-page-ID Ad Library URL instead. Every target is capped at 100 rows; use multiple targets for larger batches.
⬆️ Output
One row per ad, per target. Real row from a live run, trimmed for length:
{"adId": "388120997678322","pageName": "adidas","pageId": "1497383683837785","pageCategories": ["Product/service"],"pageLikeCount": 43617936,"state": "INACTIVE","isActive": false,"startDate": "2024-09-26T07:00:00.000Z","endDate": "2026-05-20T07:00:00.000Z","bodies": ["Conheça e compre todas as coleções e os principais lançamentos da adidas pelo app!"],"cardTitles": ["Chuteira Mundial Team Unisex","Chuteira Samba Classic Homem","Tênis Samba Classic Homem"],"ctaTexts": ["Shop now"],"ctaTypes": ["SHOP_NOW"],"observedLinkUrls": ["https://www.adidas.com.br/chuteira-mundial-team/019228.html"],"imageUrls": ["https://scontent.xx.fbcdn.net/v/t39.35426-6/..."],"publisherPlatforms": ["FACEBOOK", "INSTAGRAM"],"displayFormat": "DPA","coverageStatus": "CAPPED","changeEventId": "7b31a4f7b7b0c5aee47c1ddedb4de8b1973f3ef95b6a82d17da1b5eaab0dcf19","changeStatus": "NEW","observedAt": "2026-08-20T12:03:44.512Z"}
Export as JSON, CSV, Excel, XML or RSS, or pull it straight from the Apify API.
Built-in dataset views
changes— the monitoring view: status, changed fields, advertiser, dates and direct Ad Library link.creativeResearch— a visual swipe-file view with creative preview, copy, CTA, format and landing links.allData— every normalized field for API and spreadsheet work.
What is in every row
| Group | Fields |
|---|---|
| Ad identity | adId, collationId, collationCount, adArchiveAdCount |
| Advertiser | pageName, pageId, pageCategories, pageLikeCount, pageProfileUri, pageProfilePictureUrl |
| Copy | bodies, cardTitles, cardDescriptions, cardCaptions |
| Call to action | ctaTexts, ctaTypes |
| Creatives | imageUrls, videoUrls, displayFormat |
| Destination | observedLinkUrls |
| Delivery | state, isActive, startDate, endDate, publisherPlatforms |
| Disclosure | reachEstimate, spend, currency, impressionsText, categories, isPolitical |
| Change tracking | changeEventId, changeStatus, changedFields, materialFingerprint |
| Run context | country, query, queryKind, coverageStatus, observedAt |
Meta publishes reach and spend for political and EU ads only. For ordinary commercial ads those fields stay null — the Actor never invents a number to fill a column.
💰 How much does it cost?
| Event | Price |
|---|---|
| Run start | $0.02 |
| Baseline result | $0.70 / 1,000 |
| Change result | $1.10 / 1,000 |
Real examples:
| What you run | You pay |
|---|---|
| 100 ads from one brand | ~$0.09 |
| 1,000 ads across 10 keywords | ~$0.72 |
| Daily Changes watch on 3 targets, 100 ads each | ~$0.35 per run |
The run-start event is charged once by the Actor after valid input. Baseline rows are charged only when accepted into your dataset. In Changes mode, every delivered NEW, UPDATED, UNCHANGED and safely proven ENDED row is paid because every repeat performs a fresh live scan; state reads/writes, summaries, failed rows and suppressed rows are not charged. A stable changeEventId distinguishes normal scan revisions while identifying a rare post-delivery replay. A delivery guard blocks automatic re-billing if the change state cannot be committed. You are not billed separately for compute, network use or storage. The current price does not include browser continuity; activating that bounded layer requires a separate fixed event and a separate pricing approval.
Run the same Changes query sequentially, never concurrently against the same change store. If a run reports CHANGE_DELIVERY_RECOVERY_REQUIRED, leave its guard intact and inspect the prior run's dataset and charged-event read-back before support clears it. This deliberate fail-closed state avoids guessing whether a prior delivery was billed.
The prices shown are the Free-tier rates. Apify subscription tiers receive the lower rates displayed on the Pricing tab.
📊 Measured, not estimated
Every figure below comes from private cloud runs through 2026-08-24 and was read back from the Apify API after billing settled. These are measured platform costs, not buyer prices; source conditions still vary.
| Test shape | Result | Cost per 1,000 |
|---|---|---|
| One keyword, 5 ads at 256 MB (3 runs) | 5/5 CAPPED each | $0.234–$0.250 |
| Numeric-page-ID URL, 25 ads | 25/25 CAPPED | $0.065 |
| One keyword, 100 ads (3 runs) | 100/100 CAPPED each | $0.057–$0.105 |
| 10 keywords × 100 ads at 256 MB | 1,000 delivered, 937 globally unique | $0.030 |
| Changes, first snapshot | 60 NEW | $0.048 |
| Changes, repeat run | 60 UNCHANGED, zero false UPDATED/ENDED | $0.044 |
| Historical guarded-continuity release samples, 50 ads | 50/50 CAPPED; used to size the separate fixed event | $0.447–$0.491 |
Field coverage measured across the 1,000-row batch:
| Field | Filled |
|---|---|
| Advertiser identity, state, start date | 100% |
| Creative asset URL | 99.3% |
| Ad body text | 97.2% |
| Call to action | 93.0% |
| Destination link | 91.8% |
Where Meta does not publish something, the field stays empty. No value is ever invented to fill a column.
✅ How do I know the data is complete?
Most scrapers hand you rows and let you guess whether that was everything. This one tells you, per target:
| Status | Meaning |
|---|---|
COMPLETE | The source ran out of ads. You have all of them. |
CAPPED | Your result limit was reached first. More ads exist. |
PARTIAL | Rows are valid, but neither the cap nor the end was reached. |
EMPTY | Proven zero matching ads — not a silent failure. |
CHALLENGED | Meta blocked the read. Reported, never disguised as empty. |
This matters most for change tracking. An incomplete run can never produce an ENDED event — otherwise a slow network would look like your competitor switching off twelve campaigns. The Actor keeps the last known complete snapshot even after a partial run, so a temporary hiccup cannot corrupt tomorrow's comparison.
The trade-off is deliberate: this Actor would rather tell you an ad is still running than wrongly tell you it stopped. COMPLETE requires the source to be exhausted within the verified 100-row and 20-page per-target limits; increasing the number of targets does not turn a capped target into a complete one.
⚡ Automation ideas
Use your own private Apify Task or API call for a daily competitor watch, a weekly multi-target Changes report, or a one-off creative swipe file. Task creation, schedules and outbound alert workflows are separate setup steps; this release does not create or publish them.
Need Google ads too? Use the companion Google Ads Transparency Scraper & Change Tracker — same output philosophy and the same change-tracking guarantees.
🤖 For AI agents / MCP
This public, limited-permission Actor can be discovered and run through the hosted Apify MCP server. Use it when an agent needs current Meta competitor-ad creatives, source-backed ad fields, or a scheduled changefeed.
Example prompts:
Track what ads Nike is running on Facebook and Instagram in the US.Return only meaningful Meta ad changes for these competitor pages.Build a source-backed Meta creative swipe file with copy, CTA, media, and landing links.
Connect the standard Apify MCP server; no Actor-specific MCP server is required.
❓ FAQ
Is scraping the Meta Ad Library legal? The Ad Library is a public transparency tool that Meta publishes deliberately, and it shows the same data to anyone without logging in. That said, laws differ by country and by what you do with the data afterwards. You are responsible for your own use — if you plan something commercial or large-scale, get your own legal advice.
Why not just use Meta's official API?
Meta's ads_archive API only returns political and social-issue ads, plus housing, employment and credit ads in the US. Ordinary commercial ads have never been available through it outside the EU. For competitor research on normal brands, the Ad Library web data is the only source.
How far back does the data go? Meta keeps commercial ads visible for about 90 days and political ads for seven years. That is a Meta limit, not an Actor limit — which is exactly why change tracking is worth starting early: your own history keeps growing after Meta drops theirs.
Will I get duplicate rows? Deduplication happens inside each target. If the same ad matches two of your keywords, you get two rows — one per query context — because most buyers want to know which query found it. The run summary reports both delivered rows and globally unique ad IDs.
Can I run this on a schedule?
Yes. Use Apify Schedules and set productLevel to CHANGES. Each run returns the monitored snapshot with every delivered row labelled, so an automation can filter NEW, UPDATED and ENDED while still retaining UNCHANGED context. Combine it with webhooks or the Apify integrations for Slack, Zapier or Make to get alerts.
What if Meta changes something?
Every run reports coverage and route health. AUTO_GUARDED permits one bounded browser-continuity attempt only when its separate fixed PPE event is present at a safe runtime price. Under the current three-event pricing that event is absent, so the Actor fails closed before browser work instead of hiding an incomplete result or an unbounded cost. Choose HTTP_ONLY when you always want the lowest-cost route with no continuity attempt.
🔐 How your run is handled
- Live source access is restricted to the managed cloud runtime. Local execution fails closed before source access.
- Sensitive session and network details are not part of public rows or summaries.
- Media binaries are not downloaded — their URLs are already in the source data, so you get the links without paying for the bytes.
- The run summary records intended, charged, delivered, free and suppressed events, plus coverage and any controlled limit reached.
💬 Feedback
Found a field that should be there, a target type that fails, or a filter you need? Open an issue on the Actor's Issues tab. Bug reports with the run ID get fixed fastest.