Facebook Ads Library Competitor Tracker avatar

Facebook Ads Library Competitor Tracker

Pricing

from $590.00 / 1,000 competitor reports

Go to Apify Store
Facebook Ads Library Competitor Tracker

Facebook Ads Library Competitor Tracker

Track competitor Facebook and Instagram ads using Meta Ad Library data. Detect new and stopped ads, copy, CTA, landing-page, offer, creative, and media-mix changes over time.

Pricing

from $590.00 / 1,000 competitor reports

Rating

0.0

(0)

Developer

Furkan Toluç

Furkan Toluç

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

4 days ago

Last modified

Share

Meta Ads Competitor Change Radar

Track new, stopped, changed, long-running, and variant-heavy Facebook and Instagram ads by competitor.

Meta Ads Competitor Change Radar is a stateful competitive-intelligence Apify Actor. It answers one narrow question: What changed in my competitors' public Meta advertising since the last time I checked?

It is designed for paid media agencies, DTC brands, performance marketers, competitive-intelligence teams, and growth marketers. It is not a generic scraper, performance detector, AI analyzer, or dashboard.

What it does

For each competitor, the Actor:

  1. validates one HTTPS Facebook Page or advertiser-scoped Meta Ad Library URL;
  2. calls curious_coder/facebook-ads-library-scraper in an isolated child run;
  3. normalizes the public evidence and validates that it represents one advertiser;
  4. compares it with the last successful snapshot stored in a named key-value store;
  5. detects supported changes using stable ad IDs;
  6. groups conservative creative families and extracts duration, media, CTA, landing-domain, and English-oriented offer signals;
  7. writes one concise Dataset item per competitor; and
  8. advances state only after the report has been accepted.

The parent Actor does not scrape Facebook directly. It requires no Meta login or Meta API token. It uses the Apify run's authenticated execution context to call the upstream Actor, whose usage may have its own cost.

Input

{
"monitorKey": "skincare-us",
"competitors": [
{
"name": "Competitor A",
"pageUrl": "https://www.facebook.com/examplebrand"
},
{
"name": "Competitor B",
"pageUrl": "https://www.facebook.com/examplebrand2"
}
],
"country": "US",
"maxAdsPerCompetitor": 100,
"durableAdDays": 30,
"resetBaseline": false,
"debug": false
}

Reuse the same monitorKey, country, and normalized competitor name on future runs. That tuple selects the previous snapshot. The first successful run creates a BASELINE; later runs compare against it. resetBaseline: true deliberately ignores the previous snapshot and replaces it only after successful report output.

The MVP accepts 1–5 competitors, requests 20–250 ads per competitor, and uses a 7–180 day long-running threshold. URLs must use HTTPS and a real facebook.com host or subdomain. Keyword inputs are not accepted. ALL is not accepted as a country because its reliability has not been established for the upstream source.

Change language

  • LIKELY_NEW: a previously unseen, high-confidence ad ID has a start time at or after the previous snapshot minus a six-hour clock-skew window.
  • NEWLY_OBSERVED: a previously unseen stable ID clearly predates the prior snapshot, or its start date is unknown. It is not presented as a newly launched ad.
  • STOPPED_CONFIRMED: the same high-confidence ID was previously active and is now explicitly inactive or has acquired a credible end date.
  • NOT_OBSERVED_THIS_RUN: a previously observed high-confidence ID is absent from the current sample.
  • REACTIVATED: the same high-confidence ID changed from explicitly inactive to active.
  • COPY_CHANGED, CTA_CHANGED, and LANDING_CHANGED: both snapshots contain evidence for the relevant field and its deterministic fingerprint changed on the same stable ID.

Absence never proves an ad stopped. Meta Ad Library results can be sampled or limited, so absence produces NOT_OBSERVED_THIS_RUN, never STOPPED_CONFIRMED. Disappearing low-confidence derived IDs do not produce strong disappearance or stopped claims.

The status is CHANGES_DETECTED only when there is at least one likely-new, explicitly stopped, reactivated, or supported copy/CTA/landing change. NEWLY_OBSERVED or NOT_OBSERVED_THIS_RUN alone yields NO_CONFIRMED_CHANGE.

Current snapshot intelligence

Every successful report includes observed/active/inactive counts, evidence coverage, media mix, top CTAs and landing domains, deterministic offer signals, up to ten oldest active ads, long-running counts, and conservative creative-family counts.

LONG_RUNNING means only that an ad is explicitly active and its public dates show at least durableAdDays of duration. It does not establish profitability.

VARIANT_HEAVY means an observed creative family contains at least three related variants. It does not establish spend, scaling, conversion quality, or profitability.

Offer extraction is deterministic and English-focused. It recognizes explicit signals such as percentage or fixed discounts, free shipping/trials/consultations/gifts, BOGO, promo codes, and limited-time phrases. It does not infer ambiguous offers.

Creative-family grouping

Grouping is deterministic and false-merge averse:

  1. equal Meta collationId: confidence 1.0;
  2. exact creative fingerprint: confidence 0.95;
  3. token Jaccard similarity ≥ 0.82, only with the same known media type and exactly the same registrable landing domain: confidence 0.75.

The implementation uses Union-Find. It does not use image similarity, embeddings, OCR, media downloads, or AI.

Evidence strength and report threshold

Evidence strength is a transparent 0–100 score:

round(
stableIdCoverage × 45
+ startDateCoverage × 20
+ activeStatusCoverage × 20
+ contentCoverage × 15
)

A successful report requires a succeeded child run, at least one valid normalized ad, unambiguous advertiser identity, stable-ID coverage of at least 70%, and evidence strength of at least 60. Failures produce an uncharged analysis_error and never overwrite prior state.

Output

The default Dataset contains exactly one item per requested competitor: either a competitor_report or an analysis_error. Its overview surfaces competitor, status, evidence, observed and active ads, likely new, confirmed stopped, long-running, variant-heavy families, primary change, and snapshot time.

The default run key-value store contains:

  • OUTPUT: run-level counts;
  • REPORT.md: a human-readable report; and
  • EVIDENCE.json: normalized evidence from the current run only.

With debug: true, the default store also receives at most five raw and five normalized diagnostic records per competitor. Debug output never includes credentials.

Persistent comparison state lives separately in the named store meta-ads-change-radar-state-v1 (configurable through STATE_STORE_NAME). Keys are state- plus 24 hexadecimal SHA-256 characters derived from monitor key, country, and normalized competitor name. State stores only compact diff evidence, uses schemaVersion: 1, and increments a revision. A compare-before-write check preserves existing history if concurrent runs race.

If the confidently resolved page ID changes for the same state key, the Actor reports COMPETITOR_IDENTITY_CHANGED and creates a fresh baseline instead of comparing different advertisers.

Upstream call

One child Actor run is made per competitor, with controlled concurrency. The generated input is exactly:

{
"urls": [
{
"url": "<validated and normalized competitor Facebook URL>"
}
],
"scrapeAdDetails": false,
"limitPerSource": 100,
"scrapePageAds.activeStatus": "all",
"scrapePageAds.sortBy": "most_recent",
"scrapePageAds.countryCode": "US",
"runTag": "<monitorKey>-<timestamp>-<competitorIndex>"
}

limitPerSource and countryCode reflect public input. No period is set, because that would damage long-running-ad evidence. No count, proxy override, or Meta credential is passed. Dataset retrieval is paginated and stops at maxAdsPerCompetitor + 50. Only SUCCEEDED child runs are analyzed.

Environment variables:

META_ADS_ACTOR_ID=curious_coder/facebook-ads-library-scraper
META_ADS_CHILD_CONCURRENCY=2
META_ADS_CHILD_TIMEOUT_SECS=300
STATE_STORE_NAME=meta-ads-change-radar-state-v1
ENABLE_REPORT_CHARGING=false

Monetization scaffold

Charging is disabled by default and must remain disabled for initial private validation. When explicitly enabled later, successful BASELINE, CHANGES_DETECTED, and NO_CONFIRMED_CHANGE reports are pushed with the single custom event competitor_report. State advances only if that event is accepted. Analysis errors are always pushed without a paid event. No dollar price is hard-coded.

When Pay-Per-Event is later configured in Apify Console, remove or avoid the automatic apify-default-dataset-item paid event. The intended model is Actor Start plus competitor_report only; otherwise one result could be charged twice.

Local development

Node 24 is the production target.

npm ci
npm run typecheck
npm test
npm run build
npm run check
npx --yes apify-cli@latest validate-schema
npm audit

No live upstream run is part of automated validation. See LIVE_VALIDATION.md for the manual sequence after private deployment.

Private deployment readiness

  1. Create a private GitHub repository named meta-ads-competitor-change-radar.
  2. Push this project without local storage, .env, or credentials.
  3. Create a private Apify Actor connected to that repository.
  4. Build with the included Node 24 Dockerfile.
  5. Keep ENABLE_REPORT_CHARGING=false.
  6. Follow LIVE_VALIDATION.md, beginning with a one-competitor, 20-ad schema probe.
  7. Do not publish or enable pricing until the validation targets are met.

Limitations

  • Results are sampled public Ad Library evidence and may be truncated.
  • The upstream Actor is an external dependency and its schema can change.
  • Only publicly available Ad Library fields are used.
  • Offer extraction is English-oriented.
  • No performance metrics, spend, profitability, conversion, or ROAS inference is made.
  • Meta can change data availability or visibility.
  • The parent does not crawl landing pages, fetch media, or enrich advertisers.

Long-running, variant-heavy, and newly observed signals are public-ad-library evidence. They do not prove profitability, spend, ROAS, or conversion performance.