Scrape Facebook and Instagram ads from the Meta Ad Library in Python. Three modes — keyword search, page-level ad enumeration, single ad detail. Filter by country, ad category, active status, and media type. Built for ad spy, dropshipping research, brand monitoring, and political-ads transparency.
This Python project wraps the Facebook Ads Library Scraper Apify actor — a programmable interface to Meta's public Ad Library that pulls every currently-running (or historical) ad for any Facebook page, any keyword search, or any specific ad archive ID. Three scrape modes, 200+ country filters, ad-type filters (political/issue, employment, housing, credit, financial), pagination over Meta's GraphQL endpoints handled server-side.
Meta's Ad Library is public for transparency reasons, but the website's UI shows ~10 ads at a time and rate-limits aggressive browsing. The official API requires a registered Meta Developer App with App Review + Identity Verification for "Ads Library Browse" permissions — a process that takes weeks and gets denied frequently for indie users. This actor implements the GraphQL pagination Meta's own UI uses, but in a server-side context with proxy rotation, so you can pull hundreds of ads in one Python call.
- Competitor ad spy — enumerate every active Facebook + Instagram ad your competitors are running, with creatives + copy + CTAs.
- Dropshipping product discovery — search the library for product keywords to find which products are being actively advertised and at what volume.
- Creative inspiration / swipe file — collect ad creatives for your own marketing team's swipe file.
- Political ad transparency monitoring — scrape political/issue ads with their funding entity, impressions, and spend for journalism or research.
- Brand impersonation detection — search for your brand name to find ads from imposters running scam campaigns under your brand.
- Agency competitive pitches — pull a prospect's active ads to identify campaign gaps before pitching them.
- Trend research — search for niche keywords and see which media types (image/video/meme) currently dominate the category.
- Python 3.10+
- A free Apify account
- No Meta Developer Identity Verification needed
git clone https://github.com/pro100chok/facebook-meta-ads-library-scraper-python.git
cd facebook-meta-ads-library-scraper-python
pip install -r requirements.txt
cp .env.example .env
# paste your APIFY_API_TOKEN
python main.pymain.py enumerates the currently-active ads for five DTC consumer brands (Nike, Allbirds, Warby Parker, Casper, Lululemon) in the US — up to 30 ads each — and prints a media-type summary across the whole set.
scrapeType |
What you pass in items |
What comes out |
|---|---|---|
search |
Keywords | Every active or inactive ad whose copy / page name matches the keyword. |
pageAds |
Facebook page IDs or page slugs / URLs | Every ad running on that specific page. |
adDetail |
Ad archive IDs or ad library URLs | The full record for one specific ad (creative, copy, ranges, history). |
Meta's Ad Library is powered by an internal GraphQL endpoint with cursor-based pagination. The actor:
- Resolves your inputs (keywords → search request, page slugs → numeric page IDs, ad URLs → ad archive IDs).
- Builds the right GraphQL payload with your filters: country,
adType,activeStatus,mediaType. - Walks the result cursor through residential US proxies until
maxAdsis reached or Meta returns no more pages. - Parses each ad record into a flat schema with the platforms it ran on, media type, start/end date, body text, CTA, page info, and (for political/issue ads only) funding entity / spend / impressions.
- Pushes one ad per dataset item.
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_API_TOKEN"])
run = client.actor("pro100chok/meta-ads-library-scraper").call(run_input={
"scrapeType": "pageAds",
"items": ["nike", "adidas", "puma"],
"country": "US",
"activeStatus": "active",
"maxAds": 30,
})
for ad in client.dataset(run["defaultDatasetId"]).iterate_items():
page = (ad.get("page") or {}).get("name")
body = (ad.get("body") or {}).get("text", "")
print(f"@{page}: {body[:120]}"){
"adArchiveID": "918273645091827",
"page": { "id": "15087023444", "name": "Nike", "verification": "BLUE_VERIFIED" },
"platforms": ["FACEBOOK", "INSTAGRAM"],
"mediaType": "VIDEO",
"startDate": "2026-04-22",
"endDate": null,
"body": {
"text": "New Vaporfly 4. Faster from the first step. Shop now."
},
"snapshot": {
"ctaText": "Shop now",
"linkUrl": "https://www.nike.com/...",
"videoHdUrl": "https://video.fcmn1-1.fna.fbcdn.net/...mp4"
},
"url": "https://www.facebook.com/ads/library/?id=918273645091827"
}For political/issue ads (adType: "POLITICAL_AND_ISSUE_ADS") you additionally get fundingEntity, impressions ranges, and spend ranges.
| Parameter | Type | Required | Description |
|---|---|---|---|
scrapeType |
string | yes | search, pageAds, or adDetail. |
items |
string[] | yes | Keywords / page IDs / ad archive IDs depending on scrapeType. |
country |
string | no | ISO 3166-1 alpha-2 code or ALL for worldwide. Default US. |
adType |
string | no | ALL, POLITICAL_AND_ISSUE_ADS, EMPLOYMENT_ADS, HOUSING_ADS, CREDIT_ADS, FINANCIAL_PRODUCTS_AND_SERVICES_ADS. |
activeStatus |
string | no | active, inactive, or all. Default active. |
mediaType |
string | no | all, image, video, meme. Default all. |
maxAds |
integer | no | Cap on ads per item. 0 = unlimited (paginate until Meta returns no more). Default 100. |
maxConcurrency |
integer | no | Number of input items processed in parallel. Default 5. |
maxRetries |
integer | no | HTTP retries per page on transient errors. Default 5. |
proxyConfiguration |
object | yes | Apify Residential US strongly recommended. Meta blocks most datacenter IPs. |
| File | Demonstrates |
|---|---|
examples/01_basic_usage.py |
Keyword search → 20 results. |
examples/02_political_ads_audit.py |
Political-ads scrape with spend + impressions. |
examples/03_specific_ad_detail.py |
Full record for one ad archive ID. |
examples/04_export_to_csv.py |
Multi-brand pageAds scan + ad-longevity column. |
examples/05_export_to_google_sheets.py |
Daily snapshot into a shared Sheet. |
How is this different from the official Meta Ad Library API? Meta's own API requires you to be a verified developer with an approved Meta Developer App + Identity Verification, which takes weeks and is regularly denied. This actor scrapes the same public-facing Ad Library that anyone can browse on the web, without any registration friction.
Is it legal to scrape the Meta Ad Library? The library was explicitly created by Meta for transparency and is publicly accessible without login. Most jurisdictions treat that as fair game for scraping. The actor only retrieves data the public web UI already exposes. Consult your own legal counsel for production deployments.
Do I get spend / impressions data?
Spend and impressions are only published for ads classified as POLITICAL_AND_ISSUE_ADS. Commercial ads don't have spend disclosure — Meta only shows them as "active" with metadata, no numbers attached.
Can I download the ad creatives (videos / images)?
Yes — each ad's snapshot includes videoHdUrl / videoSdUrl / imageUrl fields with direct CDN URLs. You can fetch them via requests after the scrape. Note that these CDN URLs expire after a few hours, so download them promptly if you need to archive them.
Which countries are supported?
All 240+ countries Meta serves ads in (full ISO 3166-1 list). Use country: "ALL" for worldwide. Country filter affects which ads' country-of-origin data is returned, not where the scraper runs from.
How big can a pageAds scrape get?
Large brands run hundreds of concurrent ads. Setting maxAds: 0 returns everything Meta exposes for the page — potentially 500+ ads. The actor paginates server-side; no client-side cursor handling needed.
What if a page doesn't have any active ads? The actor returns no items for that page. Your script gets an empty result; no error.
Are ads from Instagram included?
Yes. Each ad's platforms array lists where it runs (FACEBOOK, INSTAGRAM, AUDIENCE_NETWORK, MESSENGER, THREADS). One ad creative often runs on multiple platforms simultaneously.
- TikTok Shop Scraper — for the TikTok side of social commerce.
- Threads Scraper — public Threads posts & profiles.
- SimilarWeb Traffic Data Scraper — pair ad activity with landing-page traffic data.
See all my actors at apify.com/pro100chok.
MIT — see LICENSE.
Built on top of the Facebook Ads Library Scraper Apify actor.