Instagram Ads Library Scraper - Meta Ad Library, All Filters avatar

Instagram Ads Library Scraper - Meta Ad Library, All Filters

Pricing

Pay per event

Go to Apify Store
Instagram Ads Library Scraper - Meta Ad Library, All Filters

Instagram Ads Library Scraper - Meta Ad Library, All Filters

Scrape Instagram ads from the Meta Ad Library without login: keywords, advertiser pages, ad IDs or Ad Library URLs, filtered to Instagram placements or any platform, with every Ad Library filter and EU / political transparency details. Exact caps, free total count, cross-run dedup, pay once per ad.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Automation Craft

Automation Craft

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Scrape the Meta Ad Library (Facebook, Instagram, Messenger, Audience Network, WhatsApp and Threads ads) as clean JSON, CSV or Excel. Search by keyword, advertiser page, ad ID or a pasted Ad Library URL, apply every filter the Ad Library website has, set a cap that is actually a cap, and pay only for the ads you receive. No login, no cookies, no API keys, no code.

Built around the complaints buyers leave on other Ad Library scrapers:

  • Every Ad Library filter, applied on Meta's side. Country (all 250 plus "All countries"), ad category (all, political, housing, employment, financial), active status, media type, platform, ad language, impressions date window, sort order, "targeted at country", and the political-only filters: paid-for-by, delivery region and estimated audience size. Filters that Meta applies are filters you do not pay for.
  • A cap that is honoured, billing that matches it. maxAds and maxAdsPerQuery are hard caps. You are charged exactly once per delivered ad; duplicates, filtered-out ads, total counts, summaries and empty runs are free. There is no start fee.
  • A free total count before you pay. Tick "Only count matching ads" and you get the Ad Library's own total per query at no cost, so you can size a job first.
  • Honest coverage. Every query ends with totalCount, delivered, coverage (complete, partial, empty) and stopReason (cap, end_of_results, thin_pages, blocked). You are told when the data is incomplete instead of guessing.
  • EU and political transparency, parsed into columns. Political ads carry spend, impressions and audience-size ranges as numbers; "Fetch ad details" adds EU (DSA) reach by country, age and gender, political age / gender and region distributions, payer / beneficiary data and the advertiser profile (page likes, Instagram followers, lifetime spend by disclaimer).
  • Free cross-run memory. Name a memory and later runs return only ads you have not received yet. Schedule it and you have a change feed of a competitor's new ads.
  • Derived "winning ad" filters, free. Minimum days running, minimum creative reuse (collation count), creative format, text must / must not contain, exclude pages.

This listing preselects the Instagram placement; clear the Platforms filter to get ads from every Meta surface.

30-second start

  1. Type one or more Keywords (one per line), or paste advertiser pages (facebook.com/nike, a page ID, an Instagram profile), advertiser names, Ad Library URLs (every parameter in the URL is applied) or Ad IDs.
  2. Pick the Countries and any Ad Library filters you would use on the website.
  3. Set Max ads. Start. Download JSON, CSV or Excel from the Dataset tab, or read it through the API.

Prices: $0.50 per 1,000 ads delivered. Optional add-ons: ad details $0.25 per 1,000 ads, landing-page resolution $0.20 per 1,000 pages. A full record with details costs $0.75 per 1,000 ads. Worked examples: 500 ads for three keywords = $0.25; 2,000 competitor ads with details = $1.50; a daily re-run under a memory name that finds 8 new ads among 300 known ones = $0.004; a run that finds nothing = $0.00.

What you get

One item per ad. Nested objects (images, videos, cards, details) for developers, flat columns (imageUrls, spendLower, landingDomain, ...) for spreadsheets. IDs are strings (they exceed JavaScript's number range).

Field groupFields
IdentityadArchiveId, adLibraryUrl, adId, collationId, collationCount (how many ads share this creative), pageId, pageName, pageProfileUrl, pageProfilePictureUrl, pageLikeCount, pageCategories
Status and timingisActive, startDate, endDate, daysRunning, totalActiveTimeSeconds, publisherPlatforms
CreativedisplayFormat (IMAGE, VIDEO, CAROUSEL, MULTI_IMAGES, DCO, DPA, TEXT), adText, title, caption, linkDescription, ctaText, ctaType, images[] / imageUrls, videos[] (HD, SD, preview) / videoUrls, cards[] (carousel items with their own text, link and media), extraTexts, extraLinks, extraImageUrls, extraVideoUrls, allText
DestinationlinkUrl (as served), landingUrl (l.facebook.com wrappers unwrapped), landingDomain, landingUtm, linkIsTemplate (catalogue placeholders such as {{product.name}}), landingResolved when resolution is on
Transparency (political)isPolitical, adCategories, byline (paid for by), disclaimerLabel, spendText / spendLower / spendUpper, currency, impressionsText / impressionsLower / impressionsUpper, audienceSizeText / audienceSizeLower / audienceSizeUpper, transparencyScope (POLITICAL, EU_DSA, NONE)
FlagscontainsDigitalCreatedMedia (AI disclosure), containsSensitiveContent, isAaaEligible, gatedType, hideDataStatus, stateMediaRunLabel, hasUserReported, regionalRegulation, brandedContent, ecCertificates, brazilTaxId
Details (optional)details.advertiser (page alias, category, likes, verification, Instagram handle and followers, lifetime and weekly spend by disclaimer, entity type), details.eu (targetsEu, totalReach, reachByCountry[], reachBreakdown[] by country x age x gender, age / gender / location targeting), details.political (ageGender[], regions[] with share, singleCountry), details.payerBeneficiary[], details.isAdTakenDown, details.violationTypes
ProvenancesearchTerm, searchCountry, searchAdType, queryKey, scrapedAt, changeType (NEW, UPDATED, DUPLICATE), isKnown, firstSeenAt, lastSeenAt, contentHash, charged

Which transparency numbers exist depends on the ad, not on this Actor: Meta publishes spend, impressions and audience size only for ads in the "Issues, elections or politics" category, and EU reach breakdowns only for ads that were shown in the EU. For every other ad those fields are null and transparencyScope says why. Measured fill rates from live runs at build time:

FieldCommercial ads (US, keyword)Political ads (US)
adText98%100%
title79%82%
linkUrl93%78%
landingDomain92%78%
ctaType93%77%
imageUrls40%10%
videoUrls25%55%
pageLikeCount98%97%
spendText2%100%
impressionsText2%100%
audienceSizeText2%98%
byline2%98%
collationCount80%93%
endDate100%100%

Input reference

InputWhat it does
Keywords, Keyword matchingThe Ad Library search box. "Exact phrase" is the quoted search.
Advertiser pages, Advertiser namesPage IDs, page URLs, Instagram profiles or plain names (resolved through the Ad Library's own advertiser lookup; the run summary lists the candidates). Returns the page's "See all ads" view.
Ad Library URLsPaste a URL from your browser; keyword, page, country, ad type, status, media type, platforms, languages, dates, sort and political filters are all read from it. ?id= URLs fetch that single ad.
Ad IDsLibrary IDs to fetch directly (current status, dates, creative, political numbers). Unknown IDs are reported and free.
CountriesAny of the 250 countries or All countries. Several countries = one query each (fair share of the cap). EU expands to the 27 member states (API).
Ad categoryAll, political, housing, employment, financial (the regulated categories). Political ads are the ones with spend and impressions.
Active status, Media type, Platforms, Ad languagesExactly the website's filters.
Impressions within / from / toThe website's "Impressions by date": ads that were shown in the window (an ad that started earlier and is still running matches).
SortDefault relevance, impressions high to low / low to high, most recent (grouped by launch month), as the website offers.
Only ads targeted at the countryThe is_targeted_country switch.
Paid for by, Delivery regions, Audience sizePolitical-only filters. Region names as the website shows them ("California"). Audience buckets: 100-1K, 1K-5K, 5K-10K, 10K-50K, 50K-100K, 100K-500K, 500K-1M, above 1M.
Minimum days running, Minimum creative reuse, Creative formats, text filters, Exclude pagesFree post-filters.
Max ads, Max ads per queryHard caps on delivered, charged ads. maxItems: 0 through the API means no cap.
Only count matching adsFree preflight: one count row per query, no ads, no charge.
Fetch ad details, Resolve landing pagesPaid add-ons, charged only when data came back.
Memory name, Also return already-known ads, Reset memoryCross-run dedup (named key-value store ads-library-memory-<name> in your account). Known ads are never charged.
Proxy, Parallel queries, IP retries, Stop after N empty pagesAdvanced. Leave the defaults.

Output

type: "ad" items, type: "count" rows in count mode, type: "status" rows when something could not be done (never charged), and one type: "run-summary" item at the end with per-query totalCount, delivered, pages, coverage, stopReason, the resolved advertisers, dedup stats, exact charges, proxy statistics and fill rates.

Sample item from a live run:

{
"type": "ad",
"adArchiveId": "1785179045778580",
"adLibraryUrl": "https://www.facebook.com/ads/library/?id=1785179045778580",
"adId": null,
"collationId": "974017695598335",
"collationCount": 1,
"isActive": false,
"startDate": "2026-05-07T07:00:00.000Z",
"endDate": "2026-06-29T07:00:00.000Z",
"daysRunning": 53,
"totalActiveTimeSeconds": null,
"pageId": "721404351056614",
"pageName": "IControl: Easy Widgets Themes",
"pageProfileUrl": "https://www.facebook.com/61578892468353/",
"pageProfilePictureUrl": "https://scontent-lga3-2.xx.fbcdn.net/v/t39.35426-6/695177587_1511487320476777_920753808075...",
"pageLikeCount": 4501,
"pageCategories": [
"Topic"
],
"pageIsDeleted": false,
"publisherPlatforms": [
"FACEBOOK",
"INSTAGRAM",
"AUDIENCE_NETWORK",
"MESSENGER",
"THREADS"
],
"displayFormat": "IMAGE",
"adText": "❤️Aesthetic presets for your phone✨",
"title": "🥰a FREE and personalized APP for you",
"caption": "play.google.com",
"linkDescription": null,
"linkUrl": "http://play.google.com/store/apps/details?id=com.icontrol.easy.widgets.themes",
"landingUrl": "http://play.google.com/store/apps/details?id=com.icontrol.easy.widgets.themes",
"landingDomain": "play.google.com",
"landingUtm": null,
"linkIsTemplate": false,
"ctaText": "Install now",
"ctaType": "INSTALL_MOBILE_APP",
"images": [
{
"url": "https://scontent-lga3-3.xx.fbcdn.net/v/t39.35426-6/689490050_1634784394244050_406178336346...",
"resizedUrl": "https://scontent-lga3-2.xx.fbcdn.net/v/t39.35426-6/691720374_1271927545153646_343053186879..."
}
],
"imageUrls": [
"https://scontent-lga3-3.xx.fbcdn.net/v/t39.35426-6/689490050_1634784394244050_406178336346..."
],
"videos": [],
"videoUrls": [],
"videoPreviewImageUrls": [],
"cards": [],
"cardCount": 0,
"extraTexts": [],
"extraLinks": [],
"extraImageUrls": [],
"extraVideoUrls": [],
"allText": "❤️Aesthetic presets for your phone✨\n🥰a FREE and personalized APP for you\nplay.google.com",
"adCategories": [
"UNKNOWN"
],
"isPolitical": false,
"byline": null,
"disclaimerLabel": null,
"spendText": null,
"spendLower": null,
"spendUpper": null,
"currency": null,
"impressionsText": null,
"impressionsLower": null,
"impressionsUpper": null,
"impressionsIndex": -1,
"audienceSizeText": null,
"audienceSizeLower": null,
"audienceSizeUpper": null,
"transparencyScope": "NONE",
"targetedOrReachedCountries": [],
"countryIsoCode": null,
"gatedType": "ELIGIBLE",
"isAaaEligible": true,
"containsDigitalCreatedMedia": false,
"containsSensitiveContent": false,
"hideDataStatus": "NONE",
"stateMediaRunLabel": null,
"hasUserReported": false,
"reportCount": null,
"isReshared": false,
"brandedContent": null,
"event": null,
"brazilTaxId": null,
"additionalInfo": null,
"ecCertificates": [],
"regionalRegulation": {
"finserv": {
"is_deemed_finserv": false,
"is_limited_delivery": false
},
"tw_anti_scam": {
"is_limited_delivery": false
}
},
"searchTerm": "nike",
"searchCountry": "US",
"searchAdType": "ALL",
"queryKey": "term:nike:US",
"scrapedAt": "2026-09-01T18:30:38.204Z",
"changeType": "NEW",
"isKnown": false,
"firstSeenAt": "2026-09-01T18:30:38.204Z",
"lastSeenAt": "2026-09-01T18:30:38.204Z",
"charged": true
}

Using the API

Same input as the form.

curl -X POST "https://api.apify.com/v2/acts/automation_craft~instagram-ads-library-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"searchTerms": ["skincare"],
"countries": ["US"],
"activeStatus": "active",
"mediaType": "video",
"publisherPlatforms": ["instagram"],
"deliveredWithinDays": "30",
"maxAds": 100
}'
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation_craft/instagram-ads-library-scraper').call({
advertiserNames: ['Nike'], countries: ['ALL'], fetchAdDetails: true, maxAds: 200, memoryName: 'nike-watch',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.type === 'ad').length, 'ads');
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation_craft/instagram-ads-library-scraper").call(run_input={
"searchTerms": ["vote"], "countries": ["US"], "adType": "political_and_issue_ads", "bylines": ["VOTEVETS"], "fetchAdDetails": True, "maxAds": 50,
})
ads = [i for i in client.dataset(run["defaultDatasetId"]).iterate_items() if i["type"] == "ad"]

Input keys are tolerant: country names or codes, enum labels or ids, lowercase or uppercase, strings or arrays, and the common aliases other scrapers use (keyword, maxItems, startUrls, period, startDateMin) are accepted.

Recipes

  • Competitor monitoring: advertiser pages + memoryName, scheduled daily. Only new ads arrive; changeType: UPDATED (with "Also return already-known ads") flags ads whose status, dates or creative changed.
  • Winning ads: keyword + activeStatus: active + minDaysRunning: 30 + minCollationCount: 3 + sortBy: total_impressions_desc.
  • Political spend research: adType: political_and_issue_ads + bylines or regions + fetchAdDetails: true for age / gender / region distributions and lifetime spend by disclaimer.
  • EU DSA audits: an EU country + fetchAdDetails: true for reach by country, age and gender and the declared targeting.
  • Sizing a job: the same input with onlyTotalCount: true first (free).

What this Actor does NOT do

  • It does not log in and never asks for cookies or tokens, so it only sees what the public Ad Library shows. Spend, impressions and audience size exist for political ads only; EU reach data only for ads shown in the EU. Meta's ranges (">$1M", "100K-500K") are ranges, not exact numbers.
  • Very broad keywords: the Ad Library's own result pages thin out after a few hundred ads (stopReason: thin_pages, coverage: partial). Split the job by country, platform, date window or advertiser page for complete coverage.
  • It does not download media files; it delivers the CDN URLs (which expire after some days, so download what you need).
  • It does not read the aggregate "Ad Library report" spend tables, branded-content listings or the collation "summary" panel; open an issue if you need them.
  • Meta rate-limits roughly half of all residential IPs. The Actor rotates IPs automatically and the run summary shows proxy.blockedIps; a query that cannot get a clean IP is reported as coverage: blocked and costs nothing.

Sibling listings (same engine)

Changelog

  • 1.0.0: first release. Keyword, page, advertiser-name, URL and ad-ID modes; every Ad Library filter; exact caps with fair share; free total count; post-filters; cross-run memory; ad details (EU, political, advertiser); landing-page resolution; per-query coverage reporting.