Skip to content

PRO100CHOK/facebook-meta-ads-library-scraper-python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Facebook / Meta Ads Library Scraper — Python Example

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.

Apify Actor Python 3.10+ License: MIT

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.

Why scrape the Meta Ads Library?

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.

Use cases

  • 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.

Requirements

  • Python 3.10+
  • A free Apify account
  • No Meta Developer Identity Verification needed

Quick start

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.py

main.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.

Three scrape modes

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).

How it works

Meta's Ad Library is powered by an internal GraphQL endpoint with cursor-based pagination. The actor:

  1. Resolves your inputs (keywords → search request, page slugs → numeric page IDs, ad URLs → ad archive IDs).
  2. Builds the right GraphQL payload with your filters: country, adType, activeStatus, mediaType.
  3. Walks the result cursor through residential US proxies until maxAds is reached or Meta returns no more pages.
  4. 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.
  5. Pushes one ad per dataset item.

Example: competitor active ads

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]}")

Example output (commercial ad)

{
  "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.

Input parameters

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.

More examples

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.

FAQ

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.

Related actors

See all my actors at apify.com/pro100chok.

License

MIT — see LICENSE.


Built on top of the Facebook Ads Library Scraper Apify actor.