Facebook & Instagram Ads: Active Advertiser Leads
Pricing
from $1.00 / 1,000 results
Facebook & Instagram Ads: Active Advertiser Leads
Find businesses actively running Facebook & Instagram ads, with emails, phones, websites, ad and video activity, lead scores, and the option to get only what's new each run.
Pricing
from $1.00 / 1,000 results
Rating
5.0
(1)
Developer
John.Automates
Maintained by CommunityActor stats
0
Bookmarked
5
Total users
1
Monthly active users
25 days ago
Last modified
Categories
Share
Facebook & Instagram Ads Lead Finder
Find businesses actively running Facebook and Instagram ads, and get everything you need to pitch them — one row per business, not per ad.
Point it at a niche and a country. It scans the Meta Ad Library, works out which advertisers are actually worth contacting, digs up their contact details, and links you straight to their live ads so you can check any lead yourself.
What you get
One row per business. Export to CSV / JSON / Excel, or push straight into Instantly, Smartlead, Apollo, HubSpot or Pipedrive.
| Every row includes | |
|---|---|
| Business | Name, website, domain, Facebook Page |
| Contact | Email, phone, Instagram, TikTok, LinkedIn, Facebook, contact page |
| Ad activity | Active ads, video ads, new ads in the last 7 / 30 / 90 days, creative velocity, how long they have been advertising |
| Scores | Ad activity 0–100, UGC-buyer potential 0–100, contactability, and a plain-English reason to reach out now |
| Proof | A link to every live ad they are running, plus five representative ads with copy, CTA and landing page |
| History | Whether they are new to you, when you first saw them, and what they have launched since your last scan |
How it works
- Searches the public Meta Ad Library for active ads matching each of your search queries.
- Groups every ad by advertiser (their Facebook Page), merging and de-duplicating across all your queries so each business appears once.
- Calculates activity per advertiser: how many active ads, how fast they are adding new ones, how much of it is video, and how long they have been running.
- Drops any advertiser below your activity, recency or video thresholds — before doing any expensive work.
- Works out each remaining advertiser's own website from their ad destinations, and skips anything on your exclusion list.
- Visits the surviving websites and pulls public email, phone and social links.
- Checks each advertiser against your own history of previously delivered leads, labelling them new or returning.
- Scores every advertiser, attaches evidence links, and writes rows to the dataset as they finish.
Who it's for
Everyone in the list is already paying to run ads: budget exists, someone owns paid social, and they are actively buying creative. That is a warm list, not a scrape.
| Who | What they get |
|---|---|
| Paid media & marketing agencies | Outbound lists of businesses with proven advertising activity, contactable today |
| UGC creators & video editors | Brands demonstrably buying video creative — no need to sell them on the format |
| CRO & landing-page agencies | Active advertisers plus the landing pages and CTAs they are driving traffic to |
| Freelance marketers | A warm pipeline without hours spent scrolling the Ad Library |
| B2B prospectors | Companies qualified by observable behaviour rather than firmographics |
⚡ Actively maintained — patched quickly whenever Meta changes its Ad Library. Latest release, September 2026: video inside carousel and catalog ads is now counted correctly · Ad Library proof links on every lead · separate ad-activity and UGC-buyer scores · filters for recent ads, video ads, email and excluded domains · recurring runs that return only what is new.
Why it beats a generic Ad Library scraper
| A generic Ad Library scraper | This actor |
|---|---|
| Hundreds of ad rows, many from the same advertiser | One row per business |
| Every advertiser it finds | Only those meeting your activity, recency and video thresholds |
| No contact details | Email, phone, website and socials from the advertiser's own site |
| No prioritisation | Two 0–100 scores plus a plain-English reason to reach out |
| No proof | Ad Library links to the advertiser and to individual ads |
| The same list every run | Only what is new since your last scan |
The Meta Ad Library extraction is built in, so no other paid Actor or scraping service is required.
Example output
A complete record, with every field the Actor produces. This is one real row, not an abridged illustration.
{"advertiserName": "GlowLab Skincare","facebookPageId": "123456789","facebookPageUrl": "https://www.facebook.com/123456789","adLibraryPageUrl": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=US&view_all_page_id=123456789","website": "https://glowlabskincare.com","domain": "glowlabskincare.com","emails": ["hello@glowlabskincare.com"],"phones": ["+15551234567"],"instagram": "https://www.instagram.com/glowlabskincare","linkedin": null,"tiktok": "https://www.tiktok.com/@glowlabskincare","facebook": null,"contactPageUrl": "https://glowlabskincare.com/contact","activeAdCount": 19,"imageAdCount": 8,"videoAdCount": 11,"carouselAdCount": 0,"videoShare": 0.579,"adsStartedLast7Days": 5,"adsStartedLast30Days": 8,"adsStartedLast90Days": 8,"videoAdsStartedLast30Days": 5,"oldestActiveAdDate": "2026-02-09","newestActiveAdDate": "2026-09-02","creativeVelocity": "MEDIUM","advertiserStatus": "NEW","firstSeenAt": null,"lastSeenAt": null,"adsStartedSinceLastScan": 0,"ctas": ["Shop Now","Learn More"],"landingPages": ["https://glowlabskincare.com/products/vitamin-c-serum?utm_source=fb","https://glowlabskincare.com/collections/bestsellers"],"landingDomains": ["glowlabskincare.com"],"platforms": ["FACEBOOK","INSTAGRAM"],"queriesMatched": ["skincare"],"opportunityScore": 80,"adActivityScore": 77,"ugcBuyerScore": 92,"contactability": "EMAIL","signals": ["NEW_ADVERTISER","LAUNCHING_NEW_VIDEO","VIDEO_BUYER","LONG_RUNNING","HAS_EMAIL"],"opportunityReason": "High-opportunity advertiser: first time this advertiser has appeared in your scans, 8 new ads started in the last 30 days, 5 new video creatives among them, 19 active ads seen in this scan, their oldest active ad has been running 213 days, and a public business email was found.","sampleAds": [{"libraryId": "1201948300000001","adLibraryUrl": "https://www.facebook.com/ads/library/?id=1201948300000001","startDate": "2026-09-02","text": "I tried this vitamin C serum for 30 days and my dark spots faded. Here is the before and after.","cta": "Shop Now","destinationUrl": "https://glowlabskincare.com/products/vitamin-c-serum?utm_source=fb","format": "VIDEO","hasVideo": true},{"libraryId": "1201948300000002","adLibraryUrl": "https://www.facebook.com/ads/library/?id=1201948300000002","startDate": "2026-09-02","text": "Three dermatologists explain why vitamin C belongs in your morning routine.","cta": "Shop Now","destinationUrl": "https://glowlabskincare.com/products/vitamin-c-serum?utm_source=fb","format": "VIDEO","hasVideo": true},{"libraryId": "1201948300000009","adLibraryUrl": "https://www.facebook.com/ads/library/?id=1201948300000009","startDate": "2026-02-09","text": "The full routine, step by step.","cta": "Shop Now","destinationUrl": "https://glowlabskincare.com/products/vitamin-c-serum?utm_source=fb","format": "CAROUSEL","hasVideo": true},{"libraryId": "1201948300000010","adLibraryUrl": "https://www.facebook.com/ads/library/?id=1201948300000010","startDate": "2026-02-09","text": "The full routine, step by step.","cta": "Shop Now","destinationUrl": "https://glowlabskincare.com/products/vitamin-c-serum?utm_source=fb","format": "CAROUSEL","hasVideo": true},{"libraryId": "1201948300000003","adLibraryUrl": "https://www.facebook.com/ads/library/?id=1201948300000003","startDate": "2026-09-02","text": "Three dermatologists explain why vitamin C belongs in your morning routine.","cta": "Shop Now","destinationUrl": "https://glowlabskincare.com/products/vitamin-c-serum?utm_source=fb","format": "VIDEO","hasVideo": true}]}
Nullable fields come back as null rather than being omitted, so a CSV export has consistent columns. See Output fields for what each one means.
⚠️ Important: this is not ad-spend data
Active ad count is not estimated ad spend. This actor counts how many distinct ads an advertiser currently has running in the Meta Ad Library. It does not know, estimate, or imply how much money any advertiser is spending. Treat activeAdCount, videoAdCount and creativeVelocity as signals of advertising activity, not budget. Nothing in the output will ever tell you a business is "scaling" or "increasing spend", because that is not something public data supports.
Counts are also scoped to your search. activeAdCount is the number of active ads found for your search queries, not the advertiser's full Ad Library total. An advertiser running 200 ads may show 12 here if that is how many matched your keywords. Use adLibraryPageUrl to see their real, complete list. This is why the reason text says "seen in this scan".
Input
{"searchQueries": ["skincare", "serum"],"country": "US","minActiveAds": 5,"minVideoAds": 3,"requireEmail": true}
| Field | Type | Default | What it does |
|---|---|---|---|
searchQueries | string[] | ["skincare"] | Keywords to search. Use several close variations (skincare, skin care, serum, acne) to widen coverage of a niche; results are merged and de-duplicated by advertiser. |
country | string | US | Country to search, picked from a dropdown (matches the country selector on the public Ad Library site). |
maxAds | integer | 300 | The budget, and the real limiter. How many ads the run may scan across all queries. Most advertisers surface only one or two ads in a shallow scan and so fall below minActiveAds, so budget about 12x your lead target: 25 leads needs ~300 ads, 100 leads needs ~1200. Roughly one minute per 300 ads. |
maxAdvertisers | integer | 25 | The target. The run stops once this many qualified advertisers are found. Raising it without raising maxAds will not get you more leads — see the note below. |
minActiveAds | integer | 3 | Only advertisers with at least this many active ads found during the scan become leads. |
These two knobs work together.
maxAdvertisersis what you want;maxAdsis what you let the run spend to find it. If the budget runs out first you get fewer leads than you asked for, so the Actor warns you at the start when they look mismatched, and reports the measured rate for your niche at the end:
Yield: 34 advertiser(s) qualified from 300 ads scanned (0.113 per ad), short of your maxAdvertisers=100 target. At this niche's rate, reaching 100 would take about 885 ads: set maxAds=885 next run.Use that number rather than guessing — the rate varies by niche, by
minActiveAds, and (withONLY_NEW) grows as your history builds up.
Advanced filters
All optional. The first two are evaluated before any website is crawled, so they cut run time and cost as well as narrowing results.
| Field | Type | Default | What it does |
|---|---|---|---|
minAdsStartedLast30Days | integer | 0 | Only keep advertisers that launched at least this many new ads in the last 30 days. The strongest timeliness filter — it targets accounts someone is actively working right now. |
minVideoAds | integer | 0 | Only keep advertisers running at least this many active video ads (including video inside carousel and catalog formats). The qualifier for UGC, video-editing and creative pitches. |
requireEmail | boolean | false | Drop advertisers where no public email was found. Checked after the website crawl, so it trims results rather than making the run cheaper. |
excludeDomains | string[] | [] | Domains to skip — existing customers, or advertisers you have already contacted. Enter bare domains (example.com); www and subdomains match automatically. Excluded advertisers are dropped before their website is crawled. |
Recurring runs
| Field | Type | Default | What it does |
|---|---|---|---|
historyMode | enum | TRACK | TRACK labels every advertiser NEW or RETURNING and returns everything. ONLY_NEW returns only advertisers no previous run delivered — the setting for a weekly schedule. OFF disables cross-run memory. |
History is stored in your own Apify account and never shared with anyone else. Advertisers are remembered by Facebook Page ID for as long as you keep running the Actor — there is no expiry window, so NEW always means genuinely new to you rather than something the Actor forgot. An advertiser is only remembered once a row has actually been delivered, so a lead that requireEmail filtered out this week can still arrive as new next week once an email is found.
Contact enrichment
| Field | Type | Default | What it does |
|---|---|---|---|
includeContactEnrichment | boolean | true | Visit each qualifying advertiser's website for public contact info. Turn off to run faster and cheaper (Meta data only). |
maxWebsitePagesPerLead | integer | 4 | Max pages checked per advertiser website (home, contact, about, team). |
Example — a focused UGC prospecting run:
{"searchQueries": ["skincare", "serum", "acne treatment"],"country": "US","minActiveAds": 5,"minVideoAds": 3,"minAdsStartedLast30Days": 4,"requireEmail": true}
Skincare advertisers in the US running at least 5 ads, at least 3 of them video, who launched at least 4 new ads in the last month, and where an email was found.
Output fields
Every record contains every field below. Nullable fields are null when not found.
Business
| Field | Type | Description |
|---|---|---|
advertiserName | string | Advertiser / Facebook Page name |
facebookPageId / facebookPageUrl | string | null | Facebook Page ID and link |
adLibraryPageUrl | string | null | Every active ad this advertiser is running — the verification link |
website / domain | string | null | Advertiser's own website, discovered from their ads |
emails / phones | string[] | Public contact details found on the website |
instagram / linkedin / tiktok / facebook | string | null | Social profile links found on the website |
contactPageUrl | string | null | The page the contact info was found on |
Advertising activity
| Field | Type | Description |
|---|---|---|
activeAdCount | int | Active ads found during the scan (scoped to your queries — see the note above) |
videoAdCount | int | Active ads carrying video, including video inside carousel and catalog formats |
imageAdCount / carouselAdCount | int | Active ads by non-video format |
videoShare | number | Share (0 to 1) of active ads that carry video |
adsStartedLast7Days / adsStartedLast30Days / adsStartedLast90Days | int | New ads started in each window |
videoAdsStartedLast30Days | int | New video creatives launched in the last 30 days |
oldestActiveAdDate / newestActiveAdDate | string | Date range of active ads |
creativeVelocity | enum | NONE | LOW | MEDIUM | HIGH | VERY_HIGH |
ctas | string[] | Unique call-to-action button texts used |
landingPages / landingDomains | string[] | Sample ad destination URLs / all unique destination domains |
platforms | string[] | Where the ads run, e.g. FACEBOOK, INSTAGRAM |
queriesMatched | string[] | Which of your search queries surfaced this advertiser |
Recurring-run intelligence
| Field | Type | Description |
|---|---|---|
advertiserStatus | enum | NEW (no previous run delivered them) | RETURNING | UNKNOWN (untrackable) | null when history is off |
firstSeenAt | string | null | First run that delivered this advertiser |
lastSeenAt | string | null | Previous run that delivered them |
adsStartedSinceLastScan | int | null | Active ads that started after your previous scan |
What this deliberately does not claim. Only set membership is tracked — whether you have been given this advertiser before. There is no SCALING or DECLINING status, because ad counts here are scoped to whatever your search queries surfaced, so a difference between two runs would mostly measure a change in your query list rather than a change at the advertiser. adsStartedSinceLastScan is counted from each ad's own start date rather than from a difference of totals, so it undercounts rather than overstates.
Scoring
| Field | Type | Description |
|---|---|---|
opportunityScore | int | 0–100 headline score, the default sort |
adActivityScore | int | 0–100: how active and committed an advertiser this is |
ugcBuyerScore | int | 0–100: how much video creative they are demonstrably buying |
contactability | enum | NONE | SOCIAL | PHONE | EMAIL |
signals | string[] | Filterable reason tokens, most-discriminating first |
opportunityReason | string | Plain-English explanation |
Evidence
| Field | Type | Description |
|---|---|---|
sampleAds | array | A representative mix of their active ads — each with adLibraryUrl, startDate, truncated text, cta, destinationUrl, format, hasVideo |
Sample ads are deliberately a mix, not just the newest: the 2 most recent (what they are testing right now, your pitch hook), the 2 longest-running (what has survived for them, the closest thing public data offers to a performance signal), and their latest video creative.
Example rows
The same first advertiser as above, alongside two others, trimmed to the columns you would sort on. One is new to you and two have been seen before. The data is illustrative, but every score, signal and reason was produced by the actual scoring code:
[{"advertiserName": "GlowLab Skincare","website": "https://glowlabskincare.com","emails": ["hello@glowlabskincare.com"],"phones": ["+15551234567"],"activeAdCount": 19,"videoAdCount": 11,"adsStartedLast30Days": 8,"videoAdsStartedLast30Days": 5,"creativeVelocity": "MEDIUM","advertiserStatus": "NEW","lastSeenAt": null,"adsStartedSinceLastScan": 0,"opportunityScore": 80,"adActivityScore": 77,"ugcBuyerScore": 92,"contactability": "EMAIL","signals": ["NEW_ADVERTISER","LAUNCHING_NEW_VIDEO","VIDEO_BUYER","LONG_RUNNING","HAS_EMAIL"],"opportunityReason": "High-opportunity advertiser: first time this advertiser has appeared in your scans, 8 new ads started in the last 30 days, 5 new video creatives among them, 19 active ads seen in this scan, their oldest active ad has been running 213 days, and a public business email was found."},{"advertiserName": "Sunrise Botanicals","website": "https://sunrisebotanicals.co","emails": [],"phones": ["+15559876543"],"activeAdCount": 12,"videoAdCount": 7,"adsStartedLast30Days": 6,"videoAdsStartedLast30Days": 3,"creativeVelocity": "MEDIUM","advertiserStatus": "RETURNING","lastSeenAt": "2026-09-01T09:04:32.000Z","adsStartedSinceLastScan": 3,"opportunityScore": 58,"adActivityScore": 59,"ugcBuyerScore": 66,"contactability": "PHONE","signals": ["LAUNCHING_NEW_VIDEO","LONG_RUNNING"],"opportunityReason": "Medium-opportunity advertiser: 3 new ads started since your last scan on 2026-09-01, 6 new ads started in the last 30 days, 3 new video creatives among them, 12 active ads seen in this scan, their oldest active ad has been running 97 days, and a public phone number was found (no email)."},{"advertiserName": "Pure Radiance Co.","website": null,"emails": [],"phones": [],"activeAdCount": 3,"videoAdCount": 0,"adsStartedLast30Days": 0,"videoAdsStartedLast30Days": 0,"creativeVelocity": "NONE","advertiserStatus": "RETURNING","lastSeenAt": "2026-09-01T09:04:32.000Z","adsStartedSinceLastScan": 0,"opportunityScore": 21,"adActivityScore": 25,"ugcBuyerScore": 0,"contactability": "NONE","signals": ["LONG_RUNNING"],"opportunityReason": "Low-opportunity advertiser: 3 active ads seen in this scan, their oldest active ad has been running 122 days, and no public contact info was found yet."}]
Row 1 is NEW, so NEW_ADVERTISER leads its signals and the reason opens with it. Row 2 has been seen before, so it reports what changed since: 3 new ads started since your last scan on 2026-09-01.
How scoring works
All deterministic, no AI involved. Every point is traceable to a rule, so scores are reproducible and explainable.
adActivityScore — is this an active, committed advertiser?
| Signal | Weight | Rewards |
|---|---|---|
| Recent ad launches (30 days) | 45 | Accounts someone is actively working right now |
| Active ad volume | 35 | Scale of current advertising |
| Longevity of oldest active ad | 20 | A sustained programme, not a one-week test |
Recent launches outrank raw volume on purpose: an advertiser who launched ads this month is a timely conversation, and volume is the number most affected by how your keywords happened to match.
ugcBuyerScore — are they demonstrably buying video creative?
| Signal | Weight | Rewards |
|---|---|---|
| New video creatives (30 days) | 50 | The recurring purchase a creator or editor actually sells into |
| Active video ad count | 30 | An existing video library and production budget |
| Video mix | 20 | A healthy share of video, scored as a plateau rather than "more is always better" |
This score rewards video usage rather than the absence of it. A business already running and refreshing video has proven it has a creative budget, that someone owns paid social, and that it buys video — you do not have to sell them on the format, only on yourself. A business running zero video ads has proven none of those things.
Two deliberate limits. The video-mix component plateaus instead of climbing to 100%, because a 60%-video advertiser is not meaningfully a worse prospect than an 85%-video one, and a 100%-video mix usually means automated catalog feeds rather than produced creative. And a high score means demonstrated buying, not an open slot — public data cannot tell you whether an advertiser already has an agency or a creator roster.
opportunityScore — the headline sort
adActivityScore plus a bonus for being reachable (email 15, phone 8, social 5). Contactability is a bonus rather than a core component so that a business whose email sits behind a JavaScript form is not demoted for a scraping limitation.
- 70 to 100 (High-opportunity): heavy, current ad activity and reachable. Your strongest prospects.
- 40 to 69 (Medium-opportunity): solid activity, worth a look.
- 0 to 39 (Low-opportunity): lighter or older activity. Kept in the dataset so you can decide.
Sorting tip: sort by opportunityScore for general outbound, or by ugcBuyerScore for UGC, video-editing and creative pitches. They rank differently on purpose.
signals
| Token | Meaning |
|---|---|
NEW_ADVERTISER | No previous run of yours delivered this advertiser |
HIGH_VELOCITY | 10+ new ads in the last 30 days |
LAUNCHING_NEW_VIDEO | At least one new video creative in the last 30 days |
VIDEO_BUYER | 10+ active video ads |
HIGH_AD_VOLUME | 20+ active ads found |
LONG_RUNNING | Oldest active ad running 60+ days |
HAS_EMAIL | A public business email was found |
Creative velocity
Every advertiser gets a creativeVelocity rating based on how many new ads they started in the last 30 days, a quick read on how actively they are testing new creative.
| Velocity | What it means | Why it matters |
|---|---|---|
VERY_HIGH | 20+ new ads in the last 30 days | Constantly testing, always hungry for fresh creative |
HIGH | 10 to 19 new ads in the last 30 days | Active, ongoing testing cadence |
MEDIUM | 4 to 9 new ads in the last 30 days | Steady but modest testing |
LOW | 1 to 3 new ads in the last 30 days | Slow cadence |
NONE | 0 new ads in the last 30 days | Running the same creative for a while |
The weekly workflow
The setup this is built for:
- Configure a run for your niche, with whatever filters you want.
- Set
historyModetoONLY_NEW. - Schedule it weekly in Apify.
Each week you receive only the advertisers that have appeared since your last scan. A week with nothing new returns zero rows, and the log says so explicitly — that is the expected result, not a failure.
If you want to see everything again, switch historyMode back to TRACK; nothing is lost, and returning advertisers still carry lastSeenAt and adsStartedSinceLastScan so you can see what changed.
How fast and how big
- The Meta scan is the long phase. Meta returns about 10 ads per request and the actor pauses between requests to avoid being rate-limited, so expect roughly 1 minute per 300 ads. Progress is logged every 10 pages, so you can always see it moving.
- The defaults are sized for a quick first run — about a minute of scanning, enough to see exactly what the output looks like. For serious prospecting raise
maxAdsto 1000–3000 andmaxAdvertisersto 100+, and expect several minutes. - Enrichment adds a couple of minutes for a batch of 100 leads, since it visits each one's real website. Progress is logged as it goes. Turn
includeContactEnrichmentoff to skip it entirely. - The run stops once
maxAdvertisersqualified leads are found and a meaningful ad sample has been scanned, or whenmaxAdsraw ads have been scanned — whichever comes first. - Rows are written to the dataset as they finish, strongest advertisers first, so an interrupted run still delivers its best leads.
- Every website is only ever visited once per run, and results are reused for a while across runs, even if the same brand matches several of your search queries.
- Runtime scales with
maxAds; cost scales with how many advertisers pass your filters. LoweringmaxAdsis the fastest way to shorten a run; raisingminActiveAds,minAdsStartedLast30DaysorminVideoAdsis the fastest way to cut enrichment cost.
FAQ
I'm a UGC creator, not an agency. Is this actually for me?
Yes, and there is a specific way to run it. Set minVideoAds to 3 or more and sort your results by ugcBuyerScore. That gives you brands already spending money on video creative and refreshing it regularly — they have a budget for what you make, someone in-house who manages it, and a continuing need for new creative. You are not selling them on the idea of video, just on yourself.
Why doesn't a brand with zero video ads score highly for UGC?
Because "they have no video" is a guess about what a business might want, not evidence of what it buys. A brand running and refreshing video every month has demonstrated a creative budget, an owner for paid social, and repeat purchasing. A brand with none of that may simply not buy video at all. If you specifically want the whitespace pitch, sort by adActivityScore and filter for a low videoShare — the data is all there.
How do I stop getting the same advertisers every week?
Set historyMode to ONLY_NEW and schedule the run. The actor remembers, in your own account, which advertisers it has already delivered to you, and returns only ones it has not. There is no expiry: an advertiser you received a year ago will not come back as new.
Why does the actor say an advertiser is NEW when they have clearly been advertising for years?
NEW means new to your scans, not new to Meta. It is a statement about what this actor has already handed you, nothing more. An advertiser running ads since 2019 will still be NEW the first time your search surfaces them.
Is my history shared with other users of this actor? No. It is stored in a key-value store in your own Apify account, created the first time you run the actor. No other user can read it, and it is never sent anywhere.
Does this tell me how much a business is spending on ads?
No. activeAdCount, videoAdCount and creativeVelocity measure ad activity — how many ads are running and how often new ones appear — not budget. Meta's Ad Library does not expose spend for ordinary commercial advertisers, and this actor never estimates or implies one.
Why does activeAdCount look lower than what I see in the Ad Library?
Because it counts ads that matched your search queries, not the advertiser's entire library. Open adLibraryPageUrl on any row to see their complete active list. Adding more query variations raises the counts you see.
The log went quiet for minutes. Is it stuck?
Almost certainly not. The Meta scan makes one request per ~10 ads, pausing between each to avoid rate limits, so a large maxAds means a lot of requests. It logs progress every 10 pages (Meta scan progress for "skincare": 20 pages, 195/300 unique ads collected), so if you see those ticking up it is working. Individual requests are capped at 30 seconds and retried, so a genuine stall surfaces as a warning rather than silence.
Why did I get fewer leads than maxAdvertisers?
maxAdvertisers is a ceiling, not a target. If fewer advertisers meet your filters, you get fewer rows. Lower minActiveAds, clear the advanced filters, or add more searchQueries.
I set several filters and got zero results.
That is a valid outcome for a narrow niche with strict filters, not a failure — the run log says so explicitly. requireEmail combined with a high minVideoAds is the most common cause. Loosen one at a time.
A lead has no email or phone. Why keep it?
Not every business publishes contact info, but their ad activity is still a real signal, and contactability tells you at a glance what was found. Set requireEmail if you only want fully-contactable rows.
Can I search several niches at once?
Yes. Add close variations to searchQueries. Each is searched separately, then merged and de-duplicated so the same advertiser is scored once.
Do I need to configure a proxy? No. The actor automatically requests a residential proxy for its Meta traffic (Meta rate-limits shared datacenter IPs aggressively) and falls back gracefully if your account does not have one. Nothing to turn on.
Is this allowed? It collects publicly visible ad and business information straight from Meta's own public Ad Library and each business's own website. You are responsible for using the data in line with applicable laws and platform terms, including marketing and anti-spam rules (e.g. CAN-SPAM, GDPR) when you run outreach.
Limitations
- Meta's Ad Library only shows ads currently classified as active; an advertiser that paused ads the same day will not appear.
activeAdCountreflects ads matching your search queries, not an advertiser's full library. UseadLibraryPageUrlfor the complete picture.- Very high-volume advertisers with many near-duplicate ads (which Meta itself groups together) may show a lower
activeAdCountthan their true total. - Video detection reads the actual creative and covers carousel and catalog video, but if Meta serves no playable asset for an ad it will be counted as non-video. The error direction is undercounting, never overcounting.
- Contact info depends on what a business actually publishes; a real, active advertiser can still come back with no email or phone.
- Cross-run history identifies advertisers by Facebook Page ID. The rare advertiser without one cannot be tracked, shows
advertiserStatus: UNKNOWN, and is always returned rather than silently dropped. advertiserStatus: NEWmeans new to your scans, not new to Meta. An advertiser running ads for years is stillNEWthe first time your search surfaces them.- History is per Apify account and has no expiry. It is not shared between users, and it does not carry over if you run the actor from a different account. Up to 50,000 advertisers are remembered — roughly 60 years of a weekly run — after which the least-recently-delivered are dropped first.
- To deliberately revisit advertisers you have already received, switch
historyModetoTRACK, which returns everything and labels each rowNEWorRETURNING. - Score thresholds are currently set to sensible defaults rather than statistically calibrated ones. They rank advertisers reliably against each other; treat the absolute numbers as a priority order, not a precise measurement.
activeAdCountandcreativeVelocityare activity signals, not ad spend. See the note above.
Contact / feedback
Bug reports, feature requests, and use-case tips are welcome. Email the developer at leafydevjr@gmail.com.