Meta Ad Library scraper artworkFacebook & Instagram

Meta Ad Library Scraper.

Collect the Facebook and Instagram ads your competitors are running. Look for repeated offers and messages, then use those examples to plan your own creative tests.

Run on Apify

Ways to use this scraper.

Try these examples for marketing, growth and competitor research.

01

Prepare a competitor creative brief

If you run a subscription brand, track five competitors every Monday. Group new ads by the problem they address, the promise they make, the proof they use and the offer. Pick three angles for your next round of tests.

You'll have a Google Sheet with creative links, hook categories, your notes and a proposed test.

02

Follow a seasonal promotion

Collect ads daily around a seasonal sale. Compare new ad IDs and copy changes to see when competitors introduce discounts, bundles or delivery promises.

Keep a launch timeline and an offer library with your annotations.

03

Find advertisers you haven't been following

Search a category such as running shoes to find advertiser pages beyond your current shortlist. Review the results before adding them to your regular watchlist.

Build a broader competitor list and decide which advertisers to research first.

FROM FIRST RUN TO REPEATABLE WORKFLOW

Your first run, step by step.

  1. Open the Actor on Apify, select its Input tab and switch to the JSON editor if you want to paste a configuration.
  2. In the JSON editor, replace the entire input with the example. Change ZARA to your page name or numeric page ID. In the form editor, also clear the prefilled pageID so you do not collect a second advertiser.
  3. Start with one country, active ads and a limit of 50. Keep the residential proxy enabled. Leave dates blank for this first check, then add a date window after you confirm the page match.
  4. Start the run and watch the log. Check which targets and filters were actually read before assuming an empty result means nothing exists.
  5. Open Storage → Dataset, inspect several records and export JSON for nested data or CSV for a first spreadsheet review.
First-run configuration
{
  "pageIDs": ["ZARA"],
  "country": "GB",
  "activeStatus": "active",
  "maxAds": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}

Paste this into the Actor’s JSON input editor. Replace the example targets with yours before running.

Check the current input form on Apify

Choose how to search.

Choose a page when you know the advertiser, or a keyword when you want to discover ads around a topic. These are separate searches: a keyword does not automatically narrow every page you entered.

Search methodWhen to use itWhat changes
Advertiser or brand nameWhen to use itYou have a competitor watchlist.What changesProvide numeric page IDs, names, usernames or Facebook page links. Names are resolved first: verified matches win; multiple unverified exact matches can expand into several pages.
Keyword discoveryWhen to use itYou want to find relevant results before choosing specific targets.What changesSeveral topic searches sharing the same country, dates and match type. They share one maxAds cap, so overlapping results are deduplicated rather than counted twice.
Ad Library URLsWhen to use itYou already configured the search on the source website.What changesPaste page, keyword-search or individual-ad URLs. A search URL’s country, dates and status override global settings; a single-ad URL fetches that ad without those filters.

The difference that matters

Start of a delivery window, using YYYY-MM-DD. Ads started earlier can still match if they ran during the window. Equal start and end dates are widened by one day.

Compare the related scraper

Every input, explained.

Use the exact field names below in JSON. In Apify’s form, enter list items separately, choose filters, and keep numbers and booleans in their proper types.

Default and prefill are different. A default applies when you omit a setting; a prefill is an example already entered in Apify’s form. Review prefilled targets and limits before every run. Some settings have no schema default. You still need to supply at least one supported target.

Targets and search inputs6
adLibraryUrls
List

Paste page, keyword-search or individual-ad URLs. A search URL’s country, dates and status override global settings; a single-ad URL fetches that ad without those filters.

adLibraryUrl
Text

The single-URL version of adLibraryUrls. Use one field or the other for clarity. Ordinary Facebook page links use your global filters.

pageIDs
List

Provide numeric page IDs, names, usernames or Facebook page links. Names are resolved first: verified matches win; multiple unverified exact matches can expand into several pages.

pageID
TextForm prefill: 15087023444

One page, using the same forms as pageIDs. Clear the form’s prefilled page when you only want a keyword search, otherwise both targets are collected.

keyword
Text

Find ads mentioning one topic across advertisers. This is separate from page lookup and runs alongside any page targets you left in the input.

keywords
List

Several topic searches sharing the same country, dates and match type. They share one maxAds cap, so overlapping results are deduplicated rather than counted twice.

Markets, dates and filters5
searchType
TextDefault: keyword_unordered

keyword_unordered matches words in any order. keyword_exact_phrase requires them together in that order. It only affects keyword searches; a pasted URL’s search_type takes precedence.

Suggested JSON values
keyword_unordered keyword_exact_phrase
minDate
Text

Start of a delivery window, using YYYY-MM-DD. Ads started earlier can still match if they ran during the window. Equal start and end dates are widened by one day.

maxDate
Text

Inclusive end of the delivery window. Together with minDate, it selects ads running during the period, not only ads first created during it.

activeStatus
TextDefault: allForm prefill: active

active collects currently running ads; inactive collects stopped ads; all includes archive history. The form starts with active, but omitting this field uses all.

Suggested JSON values
all active inactive
country
TextDefault: ALL

One country code or name, or ALL for every market. Unrecognized countries fall back to ALL with a warning, so check the log if your market filter seems too broad.

Suggested JSON values
ALL US GB DE FR ES IT BR MX CA AU IN AF AX AL DZ AS AD AO AI AQ AG AR AM AW AC AT AZ BH BD BB BY BE BZ BJ BM BT BO BQ BA BW BV IO VG BN BG BF BI KH CM CV KY CF TD CL CN CX CC CO KM CK CR HR CU CW CY CZ CD DK DJ DM DO EC EG SV GQ ER EE SZ ET FK FO FM FJ FI GF PF TF GA GM GE GH GI GR GL GD GP GU GT GG GN GW GY HT HM HN HK HU IS ID IR IQ IE IM IL CI JM JP JE JO KZ KE KI XK KW KG LA LV LB LS LR LY LI LT LU MO MG MW MY MV ML MT MH MQ MR MU YT MD MC MN ME MS MA MZ MM NA NR NP NL NC NZ NI NE NG NU NF KP MK MP NO OM PK PW PS PA PG PY PE PH PN PL PT PR QA CG RE RO RU RW BL KN LC MF PM VC WS SM ST SA SN RS SC SL SG SX SK SI SB SO ZA GS KR SS LK SH SD SR SJ SE CH SY TW TJ TZ TH BS TL TG TK TO TT TN TR TM TC TV UG UA AE UM VI UY UZ VU VA VE VN WF EH YE ZM ZW
Limits, details and proxies6
proxyConfiguration
ObjectDefault: {"useApifyProxy":true,"apifyProxyGroups":["RESIDENTIAL"]}Form prefill: {"useApifyProxy":true,"apifyProxyGroups":["RESIDENTIAL"]}

Use an Apify residential proxy. Datacenter exits are often challenged. Keep useApifyProxy true and apifyProxyGroups set to RESIDENTIAL for a normal run.

maxConcurrency
IntegerDefault: 4

1-6 parallel sessions. Several targets and large date ranges can run together. Use 1 for strict ranking order or when captchas appear; the default is 4.

maxAds
IntegerForm prefill: 100

A hard cap on unique ads across the whole run, including all targets and markets. Start with 50. Leaving it empty removes this cap; a broad search can then become much larger.

maxPages
Integer

Limits pages in each date shard, not the whole run. Useful for testing; clear it for fuller coverage. Zero or empty means unlimited.

delayMs
IntegerDefault: 300

Pause between page requests, in milliseconds. Increase it when the source throttles you; reducing it does not remove network delays or the source’s rate limits.

pageSize
IntegerDefault: 30

The requested batch size, not a guaranteed result count. Meta actually paginates about 10 ads at a time; raising this value will not remove that limit.

Advanced settings and recovery8
raw
True or falseDefault: false

Returns the source structure rather than the normalized presentation. Keep false for consistent analysis columns; use true when you need the source payload for debugging or your own transformations.

proxyRotations
IntegerDefault: 3

Retries refused work with a new proxy session. More retries can recover temporary blocks but add time and traffic. Keep the default until the log shows a reason to change it.

resume
True or falseDefault: true

Saves progress about every 30 seconds so an Apify restart or migration can continue the current run. Leave it on for normal use.

continueFromLastRun
True or falseDefault: false

Continues unfinished work from the previous run with matching input. Earlier results remain in that run’s dataset. Keep false for a fresh collection or a recurring snapshot.

shardSplitThreshold
IntegerDefault: 1500

Large date ranges are split when their reported ad count exceeds this threshold. It matters only with maxConcurrency above 1. Keep 1500 unless tuning large archive runs; values below 100 become 100.

docId
Text

An internal request-document override. Leave empty: the Actor detects and refreshes stale IDs automatically. It is not an advertiser or ad ID.

proxySessionId
Text

Pins a proxy session for debugging. Leave empty for routine collection. Parallel jobs need their own sessions, so this setting is ignored when parallelism prevents a single fixed session.

impersonate
TextDefault: chrome146

The browser identity used for requests. Keep the Actor’s default unless you are diagnosing immediate blocks. It changes the request fingerprint, not the data you ask for.

This reference follows the Actor’s published input fields. Check the live form before changing a production workflow. Check the current input form on Apify.

Configurations you can copy.

Each example is a separate run. Start small, inspect the results, then increase coverage. Update the targets, countries and dates to match your question.

A weekly competitor watchlist

Collect active UK ads from two brands, with 100 unique ads across the whole run. Schedule a fresh run each week, append a collection date in Sheets and compare new creative IDs with last week’s snapshot.

A weekly competitor watchlist
{
  "pageIDs": ["ZARA", "H&M"],
  "country": "GB",
  "activeStatus": "active",
  "maxAds": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}

Find a repeated offer

Find US ads using the phrase “free shipping”. This is topic discovery across advertisers. Replace the phrase with your offer and clear any prefilled page target before running.

Find a repeated offer
{
  "keywords": ["free shipping"],
  "searchType": "keyword_exact_phrase",
  "country": "US",
  "activeStatus": "active",
  "maxAds": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}

Review a past campaign window

Use this September 2026 example to review ads delivering during a window. Change both dates for your research. These are delivery-overlap filters, so an ad may have been created before the first date.

Review a past campaign window
{
  "pageIDs": ["ZARA"],
  "country": "GB",
  "activeStatus": "all",
  "minDate": "2026-09-01",
  "maxDate": "2026-09-30",
  "maxAds": 100,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}

Run, check, export, repeat.

Use page and creative IDs as your joins, and retain source links, ad text, media and delivery dates. For commercial ads, missing spend or reach is normal; the library does not supply conversion results. Store weekly snapshots in BigQuery, flatten media arrays with dbt and build a Looker Studio view of newly observed creatives.

  1. Check the dataset and the run’s SUMMARY record. Compare the number collected with your cap, inspect failed or skipped inputs, and verify a few original source links.
  2. Keep the original IDs and add collected_at and run_id when saving results. Export CSV for flat columns; retain JSON when arrays or nested details matter.
  3. Save the tested configuration as an Apify Task and schedule it. For repeated snapshots, leave continueFromLastRun false. Deduplicate new records by source ID while retaining each observation date.
  4. In Make or n8n, wait for a successful run, fetch its dataset and map fields into Sheets or your warehouse. Send records to Looker Studio through a reporting table; use dbt to flatten and test warehouse models.
  5. The same JSON works with Apify’s Actor API. In Claude with Apify MCP, name this Actor, ask it to inspect the live schema, and give explicit targets, markets and result limits before it runs.

Resume is not a fresh snapshot

resume protects the current run if Apify restarts it. continueFromLastRun continues an earlier run with the same configuration; earlier records stay in the earlier dataset. Combine both datasets for the complete collection, and raise a previously reached result cap when continuing. Start fresh when you want to see what changed today.

Follow the Sheets, Claude, Looker and BigQuery setup guides
Run this Actor from the API

Save one configuration above as input.json. Set APIFY_TOKEN to your Apify API token in your terminal, then send the file as the request body.

Start the run
curl --fail-with-body --request POST \
  --url "https://api.apify.com/v2/actors/jmlp~meta-ad-library-scraper/runs" \
  --header "Authorization: Bearer $APIFY_TOKEN" \
  --header "Content-Type: application/json" \
  --data-binary @input.json

The response contains a run ID and defaultDatasetId, not finished results. Wait for the run to succeed, set DATASET_ID to that dataset ID, then fetch its items. For large datasets, use limit and offset to page through the export.

Fetch the dataset
curl --fail-with-body \
  --url "https://api.apify.com/v2/datasets/$DATASET_ID/items?format=json" \
  --header "Authorization: Bearer $APIFY_TOKEN"

Apify’s run and export API reference
Dataset export options

When the results look wrong.

Change one setting at a time, keep a small cap, and check the run summary before scaling up.

The results belong to the wrong advertiser.

Provide numeric page IDs, names, usernames or Facebook page links. Names are resolved first: verified matches win; multiple unverified exact matches can expand into several pages.

The source keeps returning empty pages or access errors.

Use an Apify residential proxy. Datacenter exits are often challenged. Keep useApifyProxy true and apifyProxyGroups set to RESIDENTIAL for a normal run.

Should I change the advanced request settings?

An internal request-document override. Leave empty: the Actor detects and refreshes stale IDs automatically. It is not an advertiser or ad ID.

The run succeeded but returned nothing

Success means the Actor finished handling the request, not that the source returned data. Check SUMMARY.inputProblem, SUMMARY.problem and the log for missing targets, unsupported filters or refused requests. Test one known target with fewer filters.

Fewer records than expected

Check the global limit, per-search or per-page limits, platform coverage and deduplication. Several searches can find the same record. A source’s headline count can include records the public endpoint does not return. Review unfinished jobs before treating the dataset as complete.

Use the results in your tools.

Google Sheets

Use Make or n8n to append records after each successful run. Remove duplicates using ad_archive_id and add collected_at. Leave columns for your own hook labels, offer notes and next test.

Read the setup
Claude + MCP

Ask Claude to collect a capped number of ads for one advertiser page, group the messages by theme and cite ad_archive_id. Check the original creatives before using the brief.

Read the setup
Looker Studio

Put the fields you need in a sheet or BigQuery table. Chart ad counts by advertiser, start date and publisher platform. Label the counts as observations from the library.

Read the setup
BigQuery + dbt

Save the raw JSON for each run with its collection date. Use dbt to unpack snapshot and keep a separate creative table keyed by ad_archive_id.

Read the setup
Copy a prompt for Claude
Prompt for Claude + Apify MCP
Use jmlp/meta-ad-library-scraper to collect up to 50 active ads for ZARA in GB. First check the Actor input schema. Group the creative messages by hook and offer, cite the original ad IDs, and propose three testable campaign hypotheses. Do not infer spend or conversion performance.

The fields you’ll get.

Keep the collection time and original IDs with your records. You’ll need them to check where a result came from or compare it with a later run.

Before you draw conclusions

Commercial ads usually don't disclose spend or reach. Meta mainly publishes those figures for political and social-issue ads. If an ad has been running for a long time, it's worth reviewing, but its age doesn't tell you its conversion rate, profitability or ROAS.

ad_archive_id
Stable ad identifier for deduplication and original-library references.
page_id / page_name
The advertiser behind the record.
is_active / start_date / end_date
Observed activity and delivery dates; dates are Unix seconds.
publisher_platform
Facebook, Instagram and other reported Meta surfaces.
snapshot
Creative copy, headline, CTA, landing-page and media information.
collation_id / collation_count
Identifiers and counts for related ad variants.

Common questions.

Can I use it without a Facebook login?

Yes. The scraper reads the public Ad Library, so it does not require a Facebook account. You still need an Apify account to run it.

Can I see which ads are winners?

You can investigate recurring messaging and long-running creatives. The library does not give you the conversion data needed to call an ad a winner.

Source and current product details: JMLP’s Meta Ad Library Actor on Apify.

Other scrapers
you might use.

Let’s talk about
your project.

Tell me what you need to collect or understand. I can help with a custom scraper, a pipeline or the analysis.

Start a project