Facebook Ad Library Scraper
Pricing
from $2.00 / 1,000 ads
Facebook Ad Library Scraper
Collect Facebook Ad Library creatives, media links and available advertiser details by keyword or Page across selected countries. Pay per delivered ad row plus a start fee.
Pricing
from $2.00 / 1,000 ads
Rating
0.0
(0)
Developer
kane liu
Maintained by CommunityActor stats
1
Bookmarked
36
Total users
4
Monthly active users
20 hours ago
Last modified
Categories
Security
Limited permissionsShare
Collect public Facebook Ad Library ads by keyword or advertiser Page, with creative text, media links and available advertiser details in exportable rows.
- Ad headlines, body text, calls to action and destination URLs.
- Images, videos and carousel cards, with available platform and date information.
- Keyword and Page searches filtered by country, status and media type.
- Optional creative variants, asset downloads and incremental monitoring.
- $2 per 1,000 delivered rows on the Free plan, plus a small start fee.
What does Facebook Ad Library Scraper do?
Facebook Ad Library Scraper collects ads from Meta's public Ad Library. Use it to compare advertiser creatives, organize campaign research or monitor newly seen ads. It returns one ad per row, not an advertiser directory or private account data.
- Keyword search: fill
searchQueryorsearchQuerieswith brands, products or topics. - Advertiser search: fill
pageIdsorpageUrlsto collect ads from particular Pages. Keywords and Pages can share a run. - Market filters: choose a two-letter
country, such asUS,GBorDE, orALLfor worldwide searches. - Details:
enrichDetailsis on by default. Available disclosure and public advertiser contact information is added to existing ad rows, not billed as separate contact rows. - Creative variants:
expandCollationsis off by default. Each expanded variant is another ad row and is billed at the same price.
What data can you extract from Facebook Ad Library?
All rows use rowType: "ad". Optional fields depend on what Meta discloses and whether enrichment succeeds.
| Field | Description | Example |
|---|---|---|
rowType | Entity represented by this row. | ad |
id | Stable row identifier, equal to the ad archive ID. | 123456789012345 |
adArchiveId | Meta's ad archive identifier. | 123456789012345 |
pageId | Advertiser Page identifier. | 1234567890 |
pageName | Advertiser name. | Example Shop |
pageProfileUrl | Advertiser's Facebook Page link. | https://www.facebook.com/example-shop/ |
title | Creative headline. | Explore our collection |
bodyText | Ad copy. | Browse this season's products. |
ctaText | Call-to-action label. | Shop Now |
linkUrl | Ad destination URL. | https://example.com/shop |
displayFormat | Creative format reported by Meta. | IMAGE |
imageUrls | Available image links. | [] |
videoUrls | Available video links. | [] |
cards | Carousel card content and links. | [] |
publisherPlatforms | Platforms named in the ad disclosure. | ["FACEBOOK", "INSTAGRAM"] |
startDate | Ad start time, when available. | 2026-10-01T00:00:00Z |
endDate | End time; omitted for an active ad. | 2026-10-12T00:00:00Z |
isActive | Active status, or null if not disclosed. | true |
spend | Disclosed spending range, not an estimate made by this Actor. | {"lowerBound":"100","upperBound":"199","currency":"USD"} |
impressions | Disclosed impression range. | {"lowerBound":"1000","upperBound":"4999"} |
euTotalReach | EU reach where disclosed. | 1200 |
euTransparency | Available EU audience disclosures. | {"euTotalReach":1200,"targetsEu":true} |
phones | Public advertiser phone entries, if available. | [] |
emails | Public advertiser email entries. | [{"value":"name@example.com","type":"business"}] |
address | Available advertiser address components. | {"full":null} |
org | Advertiser organization identity. | {"name":"Example Shop","id":"1234567890"} |
web | Advertiser website and social links. | {"website":"https://example.com","socials":[]} |
leadAbsences | Reasons contact fields are missing or unavailable. | {} |
assetKeys | Keys for successfully downloaded media files. | ["asset-123456789012345-image.jpg"] |
scrapedAt | Collection timestamp. | 2026-10-24T08:00:00Z |
searchQuery, searchType and searchedPageId identify the search that found a row. leadSource and leadReveal describe the available contact evidence. The current contact extraction leaves geo and person as null; it does not infer coordinates or named people.
How to scrape Facebook Ad Library
- Open Facebook Ad Library Scraper in Apify Console.
- Enter a keyword or advertiser Page, then choose the country.
- Set
maxResultsto a small number, such as3. - Click Start and inspect the run status and dataset.
- Download the rows or read them through the API.
With every target field empty, the Actor uses the form's sample keyword shopify and returns at most 3 rows. This example run uses normal pricing. Filling one target field selects the matching search automatically; there is no mode setting to choose.
Keyword search
Use searchQuery for one input or searchQueries for several. Duplicate keywords are merged. A brand keyword can also match ads from other advertisers that mention the brand.
Advertiser Page search
Use numeric IDs in pageIds, or Facebook Page links and exact Page names in pageUrls. Clear the prefilled keyword for a Page-only run. Unresolved Page names are skipped with a page_unresolved warning rather than replaced with another advertiser.
What to fill in
| Field | What to enter | Default |
|---|---|---|
searchQuery | One keyword, brand or topic. | Empty; form prefills shopify |
searchQueries | Additional keywords as an array. | [] |
pageIds | Numeric advertiser Page IDs as strings. | [] |
pageUrls | Page links or exact Page names. | [] |
country | Two-letter country code, or ALL. | US |
adType | all or political_and_issue_ads. | all |
activeStatus | active, inactive or all. | active |
mediaType | all, image or video. | all |
sortBy | relevancy, newest or impressions. | relevancy |
startDateFrom | Earliest ad start date, in UTC. | Empty |
startDateTo | Latest ad start date, in UTC. | Empty |
maxResults | Row limit for each keyword or Page, from 1 to 5000. | 70; form prefills 3 |
enrichDetails | Add available disclosure and advertiser contact details. | true |
maxDetails | Detail-enrichment limit; 0 means all collected ads. | 25 |
expandCollations | Expand grouped creatives into separately billed rows. | false |
downloadAssets | Save each ad's first image and first video. | false |
incremental | Exclude ads delivered by earlier matching incremental runs. | false |
Keyword example:
{"searchQuery": "shopify","country": "US","maxResults": 3}
Advertiser example:
{"pageUrls": ["https://www.facebook.com/nike/"],"country": "US","maxResults": 3}
Dates accept YYYY-MM-DD or ISO date-times. A date-only upper bound includes that whole day; undated ads are excluded when a date filter is set. Dates do not advance automatically. newest uses monthly grouping rather than guaranteeing exact timestamp order.
maxItemsandlimitare aliases formaxResults;queryandkeywordare aliases forsearchQuery.- Unknown fields do not fail the run. Close misspellings are corrected when possible; other unknown fields are ignored with a note. Invalid filter choices are ignored with a warning.
- Invalid Page links or dates stop collection with
INVALID_INPUT: <field> — <how to fix>, before any row is charged. The start fee is separate. - The Actor writes its input interpretation to
INPUT_REPORTin the default key-value store before validation finishes, including filled, corrected and ignored fields.
Output example
Illustrative ad row; optional media and disclosure fields may be absent:
{"rowType": "ad","id": "123456789012345","adArchiveId": "123456789012345","pageId": "1234567890","pageName": "Example Shop","pageProfileUrl": "https://www.facebook.com/example-shop/","title": "Explore our collection","bodyText": "Browse this season's products.","ctaText": "Shop Now","linkUrl": "https://example.com/shop","displayFormat": "IMAGE","isActive": true,"imageUrls": [],"videoUrls": [],"scrapedAt": "2026-10-24T08:00:00Z"}
Export the dataset as JSON, CSV, Excel, XML, RSS or an HTML table. JSON preserves nested contact objects and creative lists. RUN_SUMMARY records row counts and completion information; ERROR_SUMMARY explains failures.
Why use this Facebook Ad Library scraper?
- Pay for delivered rows. Row charges apply to ads written to the dataset, not unsuccessful searches; a start fee also applies.
- Keep delivered results. Rows already written remain available after a stop. A partial response can still deliver usable ads, but stopping before delivery is not guaranteed to preserve collected data.
- Understand missing data. Unavailable fields stay empty or absent instead of being invented.
- Combine inputs. Research several keywords and Pages in one run.
- Reduce setup. You do not need to set up proxies or supply a Facebook login.
How much does it cost to scrape Facebook Ad Library?
The Actor uses pay-per-event pricing. Platform usage is included in these prices.
| Apify plan | Start event | Price per row | Price per 1,000 rows |
|---|---|---|---|
| Free | $0.005 | $0.002 | $2.00 |
| Starter | $0.005 | $0.002 | $2.00 |
| Scale | $0.005 | $0.002 | $2.00 |
| Business | $0.005 | $0.002 | $2.00 |
The start charge counts one event per GB of memory, with a minimum of one event. At the default 512 MB, starting a run costs $0.005.
maxResultsapplies to each input, with a default of70. Larger requests are collected in parts of 70; expanded variants count toward the same limit.country: "ALL"caps each input at 50 rows regardless of a larger requested limit.- Free Apify plan runs are capped at 200 rows, with 10 total runs of this Actor.
- The whole run stops at Maximum cost per run, set through
maxTotalChargeUsdin the API. Available matches and this cap may reduce the number delivered.
Example: at 512 MB, three keywords delivering 5 rows each produce 15 rows. On the Free plan, the cost is 15 × $0.002 + $0.005 = $0.035. A run that delivers no rows has no row charge, but its start event can still be charged.
What happens when the run timeout is too short
Some searches, such as several searchQueries or pageUrls with enrichDetails: true or a large maxResults, can take longer than the run timeout you chose. In that case the run does not fail. It ends early with the status message "Queued on the collection backend; this run will resume automatically when results are ready (about N s)." and shows as ABORTED for a while.
When the results are ready, the same run starts again by itself, reports "Resumed: delivering N rows.", writes the rows to the same dataset and finishes as SUCCEEDED. Rows that were already delivered are skipped, so no row is delivered or charged twice. You do not need to start another run.
- This can happen at most 3 times per run. To avoid it, choose a longer run timeout for larger searches rather than a very short one. A manual abort or an unrelated failure is not the same as this automatic pause.
- The synchronous API endpoints (
run-sync,run-sync-get-dataset-items) wait at most 300 seconds and can return an empty dataset while the run is paused. For larger jobs, start the run asynchronously and read the dataset after the run reaches SUCCEEDED, or use a webhook on the "succeeded" event.
Use with AI agents and the API
Apify MCP server
Add this remote tool in a compatible client, such as Claude, ChatGPT, Cursor or VS Code:
https://mcp.apify.com?tools=lentic_clockss/facebook-ad-library-scraper
Sign in with Apify through OAuth when prompted, or send Authorization: Bearer <YOUR_APIFY_TOKEN>. The tool starts a run and returns run and dataset IDs; the agent can read rows with get-dataset-items.
Clients without remote support can use npx @apify/actors-mcp-server --tools lentic_clockss/facebook-ad-library-scraper with APIFY_TOKEN set.
Example prompt: “Find up to 3 active US ads matching shopify and show their headlines and destination links.”
Apify API
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("lentic_clockss/facebook-ad-library-scraper").call(run_input={"searchQuery": "shopify", "country": "US", "maxResults": 3})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row)
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('lentic_clockss/facebook-ad-library-scraper').call({searchQuery: 'shopify', country: 'US', maxResults: 3,});const { items: rows } = await client.dataset(run.defaultDatasetId).listItems();console.log(rows);
For HTTP, send the input as JSON to POST https://api.apify.com/v2/acts/lentic_clockss~facebook-ad-library-scraper/runs with an Authorization: Bearer <YOUR_APIFY_TOKEN> header. After completion, read GET https://api.apify.com/v2/datasets/<datasetId>/items?format=json.
Integrations
Use Apify integrations with Google Sheets, Make, Zapier, n8n, Slack, Airtable or webhooks. Set recurring collection through Apify Schedules.
FAQ
Is it legal to scrape Facebook Ad Library?
This Actor collects public data, not private account content. You are responsible for complying with applicable terms and data-protection law. Publicly visible personal data still requires a lawful basis for your intended use. This is not legal advice.
Why did my run end as ABORTED?
The run stopped before normal completion. Check its status message and log for the specific reason, including whether it was cancelled. Do not assume it will restart automatically. Inspect the dataset before starting another run; rows already delivered remain available.
How many results can I get?
maxResults accepts up to 5000 per keyword or Page, not a guaranteed number of matches. Worldwide searches allow at most 50 per input. Free-plan limits, available matches and your maximum cost can reduce the total.
Why are some fields empty?
Meta does not disclose every field for every ad. Contact details vary by advertiser; enrichment may be unavailable or stop before completion. leadAbsences explains missing contact data. A missing active-status flag remains null.
Does this return ad performance metrics?
It returns disclosed spend and impression ranges when available, commonly for political or issue ads. It does not provide private Ads Manager metrics such as click-through rate or conversions. An active ad is not proof that it performs well.
Can I monitor only new ads?
Set incremental to true. History is shared across matching keywords, Pages, country, adType and activeStatus in facebook-ad-library-checkpoints. Only delivered ads are marked seen. History retains the latest 10,000 IDs per search scope, so this is not an unlimited archive.
Can I save images and videos?
Set downloadAssets to true. The Actor attempts to save the first image and video per ad in the run's key-value store and lists successful keys in assetKeys. Files over 9 MB are skipped. Download failures do not mean the ad row is missing.
What does an empty successful run mean?
RUN_SUMMARY.emptyReason distinguishes NO_MATCH from NO_NEW_ADS for incremental searches. Neither creates a billed ad row. Check your keyword, Page, country and filters before widening the search.
Limitations
- This Actor collects Ad Library ads, not Facebook posts, groups, comments or private profiles. Non-Page target links are rejected.
- Results reflect available public disclosures, not a complete historical archive or guaranteed market coverage.
- Contact enrichment is enabled by default but does not guarantee phones, emails or addresses. Current extraction does not populate
geoorperson. - Source restrictions can reduce results or prevent collection. Disclosed spend and reach are not available for every ad.
- Creative lists are capped at 50 entries; fields such as
cardsCount,imageUrlsCountandvideoUrlsCountretain the original count when truncated. - Date filters exclude ads with no start date. Carousel is not a
mediaTypeoption; inspectdisplayFormatafter collection.
Related scrapers
More ad library and ads intelligence scrapers from the same publisher:
Browse all of our scrapers at apify.com/lentic_clockss.
Support
Report a problem or request a field through the Issues tab of this Actor's page. Include the run ID and the input you used.