The Mine Works
← All posts
tutorial June 22, 2026 · 2 min read Updated June 22, 2026

How to Scrape the Meta Ad Library in Python (Facebook and Instagram Ads, No Login)

The Meta Ad Library has no official scraping API. Learn how to extract ad copy, creative URLs, advertiser details, platforms, and run dates from Facebook and Instagram ads by keyword or advertiser, as structured JSON.

Try the scraper

The actor referenced in this article. Pay only for results delivered.

View the scraper →

The Meta Ad Library exposes every active ad running on Facebook, Instagram, Messenger, and the Audience Network. It is the most complete public database of digital advertising creative. Here is how to pull structured data from it at scale.

What each ad record contains

  • Ad creative copy (headline and body text)
  • Image and video asset URLs
  • Advertiser name and Facebook page ID
  • Platforms the ad runs on
  • Date the ad started running and (if inactive) when it ended
  • Country targeting where available

Common use cases

Competitor ad intelligence. Pull all active ads for a competitor brand and analyze copy angles, creative formats, and messaging themes. See which ads they have been running the longest (these are usually their best performers).

Creative benchmarking. Research ad creative across a category before launching a campaign. What image styles, headline lengths, and copy hooks are other brands using?

Campaign monitoring. Track when a brand launches or pauses campaigns by comparing weekly snapshots of their active ads.

Market research. Search for ads by keyword to understand how a market positions itself — pricing language, feature emphasis, emotional hooks.

Using the Apify actor

import apify_client

client = apify_client.ApifyClient('YOUR_APIFY_TOKEN')

run_input = {
    "searchTerms": ["CRM software"],
    "country": "US",
    "maxResults": 50,
}

run = client.actor('themineworks/meta-ad-library-scraper').call(run_input=run_input)

for ad in client.dataset(run['defaultDatasetId']).iterate_items():
    if ad.get('_type'):
        continue
    print(f"Advertiser: {ad.get('page_name')}")
    print(f"  Copy: {str(ad.get('ad_creative_bodies', ['']))[:120]}")
    print(f"  Platforms: {ad.get('publisher_platforms', [])}")
    print(f"  Running since: {ad.get('ad_delivery_start_time', 'N/A')}")
    print(f"  Image: {str(ad.get('ad_creative_image_urls', ['none']))[:80]}")

Competitor ad analysis

Track a specific advertiser across their entire active library:

run_input = {
    "pageIds": ["YOUR_COMPETITOR_PAGE_ID"],
    "country": "US",
    "adActiveStatus": "active",
    "maxResults": 200,
}

run = client.actor('themineworks/meta-ad-library-scraper').call(run_input=run_input)
ads = [a for a in client.dataset(run['defaultDatasetId']).iterate_items() if not a.get('_type')]

print(f"Active ads: {len(ads)}")

# Find longest-running ads (likely best performers)
from datetime import datetime
def days_running(ad):
    start = ad.get('ad_delivery_start_time', '')
    if not start:
        return 0
    try:
        return (datetime.now() - datetime.fromisoformat(start.split('T')[0])).days
    except ValueError:
        return 0

ads_with_age = [(ad, days_running(ad)) for ad in ads]
for ad, days in sorted(ads_with_age, key=lambda x: -x[1])[:5]:
    print(f"\n  [{days} days running] {ad.get('page_name')}")
    bodies = ad.get('ad_creative_bodies') or []
    if bodies:
        print(f"  Copy: {bodies[0][:200]}")

Copy pattern analysis

Find the most common headline structures:

from collections import Counter
import re

headlines = []
for ad in ads:
    bodies = ad.get('ad_creative_bodies') or []
    titles = ad.get('ad_creative_link_titles') or []
    headlines.extend(titles)
    for body in bodies:
        first_line = body.strip().split('\n')[0]
        if len(first_line) < 100:
            headlines.append(first_line)

# Find common opener words
openers = Counter()
for h in headlines:
    words = re.findall(r'\b\w+\b', h.lower())
    if words:
        openers[words[0]] += 1

print("Most common headline opener words:")
for word, count in openers.most_common(20):
    print(f"  {word}: {count}")

Platform distribution

from collections import Counter

platforms = Counter()
for ad in ads:
    for p in ad.get('publisher_platforms', []):
        platforms[p] += 1

print("Platform distribution:")
total = sum(platforms.values())
for platform, count in platforms.most_common():
    print(f"  {platform}: {count} ads ({count/total*100:.0f}%)")

Pricing

$0.003 per ad returned. Ads that fail to load are never charged.

Related Actor

Explore the scraper referenced in this article — see inputs, outputs, and pricing, then run it on Apify.

Frequently asked questions

Is there an official Meta Ad Library API? +

Meta provides a limited Ad Library API for political and social issue ads, but not for all advertisers. The scraper covers all public ads regardless of category.

What ad data does the scraper return? +

Ad creative copy, image and video URLs, advertiser name and page ID, platforms the ad runs on (Facebook, Instagram, Messenger, Audience Network), and the date range the ad has been running.

Can I track specific advertisers over time? +

Yes. Search by page ID or advertiser name and schedule weekly runs to build a timeline of their ad activity and creative rotation.