Facebook Ad Library Scraper avatar

Facebook Ad Library Scraper

Pricing

$0.50 / 1,000 results

Go to Apify Store
Facebook Ad Library Scraper

Facebook Ad Library Scraper

Scrapes ads from the Facebook Ad Library. Accepts search URLs or Facebook page URLs and returns structured ad data.

Pricing

$0.50 / 1,000 results

Rating

0.0

(0)

Developer

Practical Tools

Practical Tools

Maintained by Community

Actor stats

0

Bookmarked

104

Total users

14

Monthly active users

8 days ago

Last modified

Share

Extract ads from the Facebook Ad Library — creative, landing pages, platforms, impressions, spend, and advertiser page details — without a Facebook account or API key.

Search by keyword, pull every ad an advertiser page is running, or search for a keyword inside one advertiser's ads. Output is one clean row per ad with dates as YYYY-MM-DD, ready for CSV, Excel, or JSON.


Quick start

Search the Ad Library for a keyword

{ "keyword": "running shoes", "country": "US", "activeStatus": "active", "limitPerSource": 100 }

Get all ads from advertiser pages

{ "pages": ["https://www.facebook.com/ZapierApp", "nike", "254515547747520"], "limitPerSource": 0 }

Search for a keyword inside an advertiser's ads

{ "keyword": "free trial", "pages": ["https://www.facebook.com/ZapierApp"], "keywordWithinPages": true }

Monitor a competitor every week — schedule this and set a run tag per run:

{
"pages": ["https://www.facebook.com/ZapierApp"],
"datePreset": "last7d",
"limitPerSource": 0,
"includePageSummary": true,
"runTag": "2026-W39"
}

Political ads about a topic, exact phrase, Instagram only

{
"keyword": "climate change",
"searchType": "keyword_exact_phrase",
"adType": "political_and_issue_ads",
"publisherPlatforms": ["instagram"],
"country": "US",
"datePreset": "last30d"
}

Features

  • No login required — scrapes the public Ad Library over plain HTTP, no browser
  • Three ways in — keyword search, advertiser pages, or raw Ad Library URLs
  • Search within an advertiser — turn on keywordWithinPages to find only one advertiser's ads about a topic
  • Advertiser pages in any form — page URL, handle (ZapierApp), numeric page ID, or an Ad Library link
  • Every Ad Library filter — country, active status, ad category (political, housing, employment, credit), media type, date range, platforms, languages, exact-phrase matching
  • Per-page summary rows — total ads, active ads, platform breakdown, date range for each advertiser
  • EU transparency — EU reach with country / age / gender breakdown, targeting, payer and beneficiary, no login needed
  • Rich ad-level fields — publisher platforms, impressions band, spend and reach (political ads), collation count (number of near-identical variants), page likes and categories, AI-generated flag
  • Clean creatives — headline, body, CTA, landing page, image, video and thumbnail; carousels nested under cards
  • Two output shapes — one row per ad (default) or one row per creative card
  • Cost control — per-source and global ad limits
  • Errors in the dataset — a page that cannot be resolved produces an error row, never a silent empty run
  • Proxy-ready — optional Apify or custom proxies, usually not needed

Input

Sources

FieldTypeDescription
keywordstringA search of the whole Ad Library for this term, like the Ad Library search box.
pagesstring[]Advertiser pages: every ad each one is running. Each entry may be a page URL, a handle, a numeric page ID, or an Ad Library URL containing view_all_page_id.
urlsstring[]Searches copied from the Ad Library website, one per entry ({ "url": "…" } objects are accepted too). Everything in the URL is kept; filters you change are added only when the URL does not set them. Facebook page URLs here behave like entries in pages.
keywordWithinPagesbooleanDefault false: every entry above is its own source. true: the keyword stops being a search of its own and instead filters the pages' ads, e.g. "Model Y" inside Tesla's ads.

Provide at least one of keyword, pages, or urls. Each one is scraped independently and the results are combined in one dataset, so the default input (a keyword, a page, and a URL) yields three sets of ads. Empty entries are ignored.

Filters (apply to keyword and pages)

FieldTypeDefaultDescription
countrystringALLISO 3166-1 alpha-2 code (US, GB, DE) or ALL
activeStatusstringallall, active, inactive
adTypestringallall, political_and_issue_ads, housing_ads, employment_ads, credit_ads. Political and issue ads carry spend and reachEstimate.
mediaTypestringallall, image, video, meme, none
datePresetstring—last24h, last7d, last14d, last30d, last90d. Ads that were running at any point in the window.
startDateMin / startDateMaxstring—YYYY-MM-DD. Explicit window; overrides datePreset. Same "running at any point" semantics as Facebook's own date filter.
publisherPlatformsstring[][]Any of facebook, instagram, audience_network, messenger, threads. Empty = all.
contentLanguagesstring[][]ISO 639-1 codes (en, es, de). Empty = all.
searchTypestringkeyword_unorderedkeyword_unordered (any of the words) or keyword_exact_phrase.
sortBystringimpressions_descSent to Facebook as the sort preference. Facebook's server-rendered results currently ignore it and come back in Facebook's own order.

Limits

FieldTypeDefaultDescription
limitPerSourceinteger10Max ads per keyword, page, or URL. 0 = all.
maxItemsinteger0Max ads across the whole run. 0 = no limit. The run stops as soon as it is reached.

Output options

FieldTypeDefaultDescription
outputModestringadad = one row per ad (first card flattened, all cards under cards). card = one row per creative card.
includePageSummarybooleanfalseAdd one summary row per advertiser page (see below).
includeEuTransparencybooleanfalseFetch each ad's details: EU reach with country / age / gender breakdown, targeting, payer and beneficiary, Instagram handle and followers, page verification. One extra request per ad.
includeRawDatabooleanfalseAttach the untouched Facebook ad object as rawData.
runTagstring—Copied into the runTag column of every row.
proxyConfigurationobject—Optional proxy settings.

Output

Ad rows (default, outputMode: "ad")

{
"adArchiveID": "899524914329334",
"adUrl": "https://www.facebook.com/ads/library/?id=899524914329334",
"pageName": "Wealthsimple",
"pageID": "268452016650171",
"pageUrl": "https://www.facebook.com/wealthsimple/",
"pageProfilePictureUrl": "https://scontent.../pp.jpg",
"pageLikeCount": 123456,
"pageCategories": ["Financial service"],
"isActive": false,
"startDate": "2021-10-20",
"endDate": "2022-01-12",
"publisherPlatforms": ["FACEBOOK", "INSTAGRAM", "AUDIENCE_NETWORK", "MESSENGER"],
"impressions": ">1M",
"impressionsIndex": 39,
"spend": "CA$350K - CA$400K",
"currency": "CAD",
"reachEstimate": ">1M",
"categories": ["POLITICAL"],
"isPolitical": true,
"paidForBy": "Wealthsimple Technologies Inc.",
"disclaimer": null,
"collationCount": 1,
"collationID": "165980345735977",
"isAiGenerated": false,
"stateMediaLabel": null,
"targetedCountries": [],
"totalActiveTimeSeconds": null,
"displayFormat": "VIDEO",
"format": "video",
"isDCO": false,
"primaryText": "Receive one free stock (up to $4.5k) just for signing up!",
"headline": "Buy & sell stocks in just a few taps",
"body": "Receive one free stock (up to $4.5k) just for signing up!",
"cta": "Install Now",
"ctaType": "INSTALL_MOBILE_APP",
"destinationUrl": "http://itunes.apple.com/app/id1403491709",
"displayDomain": "itunes.apple.com",
"linkDescription": null,
"imageUrl": "https://scontent.../thumb.jpg",
"videoUrl": "https://video.../video.mp4",
"videoThumbnailUrl": "https://scontent.../thumb.jpg",
"cardCount": 1,
"cards": [{ "cardIndex": 0, "headline": "Buy & sell stocks in just a few taps", "body": "…", "cta": "Install Now", "ctaType": "INSTALL_MOBILE_APP", "destinationUrl": "…", "displayDomain": "itunes.apple.com", "linkDescription": null, "imageUrl": "…", "videoUrl": "…", "videoThumbnailUrl": "…" }],
"sourceUrl": "https://www.facebook.com/wealthsimple",
"position": 1,
"totalResults": 1032,
"runTag": "2026-W39",
"scrapedAt": "2026-09-22T16:00:00.000Z"
}
FieldDescription
adArchiveID, adUrlAd Library ID and direct link
pageName, pageID, pageUrl, pageProfilePictureUrl, pageLikeCount, pageCategoriesAdvertiser page
isActive, startDate, endDateRun status and dates (endDate is null while still running)
publisherPlatformsWhere the ad runs: FACEBOOK, INSTAGRAM, AUDIENCE_NETWORK, MESSENGER, THREADS
impressions, impressionsIndexImpressions band (e.g. 10K - 15K) and Facebook's ordinal index; only shown by Facebook for some ads
spend, currency, reachEstimatePolitical / issue ads only
categories, isPolitical, paidForBy, disclaimerAd category labels and political disclaimers
collationCount, collationIDNumber of near-identical variants of this ad, and their group ID
isAiGeneratedFacebook's "digitally created" flag
stateMediaLabel, targetedCountries, totalActiveTimeSecondsTransparency labels when Facebook provides them
displayFormat, format, isDCOFacebook's format (IMAGE, VIDEO, CAROUSEL, DCO, DPA…), our derived image / video / carousel / text, and whether the ad uses dynamic creative templates
primaryTextPost text above the creative (null for DCO, where Facebook sends template variables)
headline, body, cta, ctaType, destinationUrl, displayDomain, linkDescription, imageUrl, videoUrl, videoThumbnailUrlFirst creative card
cardCount, cardsAll creative cards (carousel cards or DCO variants), deduplicated
sourceUrlThe keyword URL, page, or URL you supplied
position, totalResultsRank within its source, and the total number of matching ads Facebook reports (capped at 50,001)
runTag, scrapedAtYour tag and the scrape timestamp
rawDataThe untouched Facebook object, only when includeRawData is on

EU transparency and payer details (includeEuTransparency: true)

Adds these columns to every ad row (or card row), plus the full adDetails object:

FieldDescription
euTotalReachEstimated Meta accounts in the EU that saw the ad at least once
payer, beneficiaryWho paid for and who benefits from the ad, as declared for EU delivery
igUsername, igFollowers, pageVerificationAdvertiser's Instagram handle and followers, and Facebook verification status (BLUE_VERIFIED…)
adDetails.euTransparencytargetsEu, totalReach, ageAudience {min,max}, genderAudience, locationAudience[] (included/excluded countries, regions, cities), reachBreakdown[] rows of {country, ageRange, male, female, unknown}
adDetails.payerBeneficiaryAll payer / beneficiary pairs
adDetails.advertiserpageLikes, pageCategory, igVerified, isPoliticalPage, isRestricted
adDetails.isTakenDown, violationTypes, isViolatingEuRulesEnforcement flags

Ads never shown in the EU have euTransparency: null. The data comes from the same request the Ad Library website makes when you click See ad details; it needs no login. If Facebook changes that query, the run emits one AD_DETAILS_QUERY_INVALID error row and continues without details.

Card rows (outputMode: "card")

Same ad-level fields, but one row per creative card with a cardIndex column instead of cardCount / cards. Use this for creative analysis where each carousel card matters.

Page summary rows (includePageSummary: true)

One per advertiser page, marked rowType: "pageSummary". Shown in the Pages view of the Output tab.

{
"rowType": "pageSummary",
"sourceUrl": "https://www.facebook.com/ZapierApp",
"pageName": "Zapier",
"pageID": "309796912374932",
"pageUrl": "https://www.facebook.com/ZapierApp/",
"pageProfilePictureUrl": "https://scontent.../pp.jpg",
"pageLikeCount": 56539,
"pageCategories": ["Software"],
"pageIsDeleted": false,
"totalAds": 1032,
"adsCollected": 50,
"activeAdsCollected": 12,
"platformBreakdown": { "FACEBOOK": 50, "INSTAGRAM": 31, "MESSENGER": 9 },
"earliestStartDate": "2024-01-24",
"latestStartDate": "2026-06-04",
"runTag": "2026-W39",
"scrapedAt": "2026-09-22T16:00:00.000Z"
}

totalAds is the count Facebook reports for your filters (so with activeStatus: "active" it is the number of ads currently live). The other counts describe the ads actually collected.

Error rows

If a source fails, the dataset gets a row with errorCode and error instead of a silent empty result. Shown in the Errors view.

errorCodeMeaning
INVALID_PAGEAn entry in pages is not a Facebook page URL, handle, or ID
PAGE_ID_NOT_FOUNDThe Facebook page could not be resolved to an advertiser ID (private, deleted, or not a page)
DUPLICATE_SOURCETwo entries resolved to the same page; its ads appear once
NO_AD_DATAThe Ad Library returned a page without ad data
CHALLENGE_FAILEDFacebook's anti-bot challenge could not be solved
AD_DETAILS_QUERY_INVALIDFacebook rejected the ad-details query (emitted once; the run continues without EU data)
REQUEST_FAILEDNetwork or HTTP failure after retries

How it works

The Ad Library server-renders the first page of results as JSON inside the HTML. The scraper:

  1. Sends a plain HTTP request with browser-like headers (no browser, so runs are cheap and fast)
  2. Solves Facebook's lightweight __rd_verify challenge if it is returned
  3. Parses the embedded search_results_connection JSON
  4. Follows the end_cursor to the next page until the limits are reached
  5. For advertiser pages, first resolves the page's numeric ID, then queries the Ad Library with view_all_page_id

Pricing

Pay per event. You are charged for what lands in your dataset, not for rows:

EventWhen it is charged
adOnce per ad, in both output modes. A six-card carousel in "one row per creative card" mode is still one ad.
ad-detailsOnce per ad whose EU transparency details were fetched successfully (only with includeEuTransparency).
apify-actor-startOnce per run, by the platform.

Error rows and page-summary rows are free. Set Maximum cost per run in the run options to cap spending; the actor stops cleanly when the cap is reached and you keep everything scraped up to that point.

Proxy

The Ad Library is a public transparency tool and works without a proxy in normal use. If you scrape very large volumes and hit blocks, add residential proxies:

"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }