Facebook Ads Competitor Monitor & Tracker
Pricing
from $100.00 / 1,000 competitor checkeds
Facebook Ads Competitor Monitor & Tracker
Track competitor Facebook and Instagram ads. Detect new, stopped, reactivated, copy, creative, and landing-page changes with before/after evidence.
Pricing
from $100.00 / 1,000 competitor checkeds
Rating
0.0
(0)
Developer
Ula Ula
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
12 days ago
Last modified
Categories
Share
Know when a competitor launches, stops, reactivates, or changes an ad - without manually comparing Meta Ad Library results every day.
This Actor turns public Facebook and Instagram ad observations into a persistent competitor monitor. It remembers the last complete observation and emits clean, auditable change events with before-and-after evidence.
Try the live demo in 60 seconds
- Keep the prefilled Nike example.
- Click Start.
- Open the Dataset tab to inspect current ads, copy, creatives, landing pages, and source links.
The demo uses all_current, so the first run returns useful data immediately.
It is a one-time snapshot and does not modify a monitoring baseline.
{"monitorId": "nike-demo-snapshot","competitors": [{"id": "nike-us","name": "Nike","ad_library_url": "https://www.facebook.com/ads/library/?active_status=all&ad_type=all&country=US&view_all_page_id=15087023444"}],"country": "US","maxAdsPerCompetitor": 10,"outputMode": "all_current","maxUpstreamChargeUsd": 0.05}
What you get
NEW- a previously unseen ad IDCOPY_CHANGED- ad text or call to action changedCREATIVE_CHANGED- creative URLs or creative fingerprint changedLANDING_PAGE_CHANGED- the normalized destination changedREACTIVATED- a previously stopped ad returnedSTOPPED- an ad disappeared from repeated complete observations or was explicitly observed as inactive- Before-and-after records for audit and reporting
- Stable event IDs for deduplication in Make, Zapier, n8n, or your own system
- A run summary even on quiet days when no changes are found
Set up daily monitoring
1. Use an exact advertiser locator
Open the advertiser in Meta Ad Library and copy the filtered URL. Put that URL
in ad_library_url. A numeric page_id or Facebook page_url also works.
Use search_term only as a fallback: keyword search can include similarly named
or unrelated advertisers.
2. Create the baseline
Change outputMode to changes, choose a stable monitorId, and start the
Actor. The first successful run creates a silent baseline. The run summary will
say that the baseline was created; an empty Dataset is expected at this stage.
For monitoring, set maxAdsPerCompetitor above the advertiser's likely total.
If a result exactly reaches the cap, the Actor treats it as partial and protects
the existing baseline from false stopped-ad alerts.
{"monitorId": "client-acme-daily","competitors": [{"id": "competitor-one-us","name": "Competitor One","ad_library_url": "PASTE_THE_EXACT_META_AD_LIBRARY_URL_HERE"}],"country": "US","maxAdsPerCompetitor": 250,"outputMode": "changes","stoppedAfterMissingRuns": 2,"maxUpstreamChargeUsd": 1}
3. Save and schedule
Click Save as a new task, then add a daily Schedule. Keep the same
monitorId; that is the key connecting today's observation with future runs.
4. Deliver alerts
Attach a run-succeeded webhook or integration to the saved task. The default
Dataset is your event feed. The OUTPUT key-value-store record is the compact
run summary for health checks and dashboards.
Useful destinations include Slack, Microsoft Teams, Make, Zapier, n8n, Google Sheets, Airtable, a CRM, a warehouse, or your own endpoint.
Output modes
| Mode | Best for | Baseline behavior | Dataset on first run |
|---|---|---|---|
all_current | Demo, research, one-time export | Does not read or update it | Current ads |
changes | Recurring monitoring | Creates or updates it safely | Empty baseline run |
all | Monitoring plus initial inventory | Creates or updates it safely | Initial ads as NEW |
Example change event
{"event_id": "evt_...","event_type": "COPY_CHANGED","monitor_id": "client-acme-daily","competitor_id": "competitor-one-us","competitor_name": "Competitor One","ad_id": "1234567890","changed_fields": ["copy"],"before": {"ad_id": "1234567890","copy": "Old promotional message","landing_url": "https://example.com/offer"},"after": {"ad_id": "1234567890","copy": "New promotional message","landing_url": "https://example.com/offer"},"detected_at": "2026-07-15T12:00:00Z","source_url": "https://www.facebook.com/ads/library/?id=1234567890"}
The event contains both normalized evidence and a source URL when the upstream
provider exposes one. A STOPPED event is an observation signal, not proof that
Meta formally ended an ad.
Reliability safeguards
Ad monitoring is only valuable when partial scrapes do not create false alerts. This Actor therefore:
- Never updates state after a failed upstream run
- Rejects capped or explicitly partial observations for baseline updates
- Protects the baseline when observed inventory collapses below 50% of the previous complete snapshot
- Requires at least two complete absences before emitting
STOPPED - Normalizes whitespace and common tracking parameters before comparison
- Emits
REACTIVATEDonce when an absent ad returns - Produces deterministic event IDs for downstream deduplication
- Honors the user's maximum run charge before starting paid competitor checks
State is isolated in a named key-value store derived from monitorId. Use a
different ID for each client, market, or independent monitor.
Inputs
Every competitor needs a stable id and one locator:
ad_library_url- recommended exact Meta Ad Library URL with filterspage_id- exact numeric Facebook page IDpage_url- public Facebook page URLsearch_term- broad keyword fallback
Other controls:
country- two-letter Meta Ad Library country codemaxAdsPerCompetitor- requested records per competitor, 1-500outputMode-all_current,changes, orallstoppedAfterMissingRuns- complete absences required beforeSTOPPEDmaxUpstreamChargeUsd- hard combined ceiling for child Actor callsupstreamActorId- advanced replacement for the default data providerupstreamInputOverrides- advanced provider-specific JSON
Pricing
You pay:
- $0.01 per Actor start
- $0.10 per successfully processed competitor
- The selected upstream Meta Ad Library provider separately, within your
maxUpstreamChargeUsdlimit - No additional platform-usage charge for this Actor
Examples for this Actor's event fees:
| Workload | Actor fee per run | Approx. Actor fee per 30 days |
|---|---|---|
| 1 competitor, daily | $0.11 | $3.30 |
| 5 competitors, daily | $0.51 | $15.30 |
| 10 competitors, daily | $1.01 | $30.30 |
Upstream charges are extra and depend on returned records and the provider's current pricing. Start with one advertiser and a small snapshot, inspect Usage, then increase the monitoring limit. The hard upstream ceiling prevents an unexpected child-run bill, but setting it too low can stop a child run early.
Use from JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('dataforge_labs/facebook-ad-change-intelligence').call({monitorId: 'client-acme-daily',competitors: [{id: 'competitor-one-us',name: 'Competitor One',page_id: '1234567890',}],country: 'US',maxAdsPerCompetitor: 250,outputMode: 'changes',maxUpstreamChargeUsd: 1,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Use from Python
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("dataforge_labs/facebook-ad-change-intelligence").call(run_input={"monitorId": "client-acme-daily","competitors": [{"id": "competitor-one-us","name": "Competitor One","page_id": "1234567890",}],"country": "US","maxAdsPerCompetitor": 250,"outputMode": "changes","maxUpstreamChargeUsd": 1,})events = client.dataset(run["defaultDatasetId"]).list_items().itemsprint(events)
Limitations
- Meta controls public availability; results may not represent an advertiser's complete portfolio
- Search terms can include unrelated advertisers
- Creative URLs can be temporary or missing
- Meta and upstream providers can change fields or pagination behavior
- This Actor does not log in, bypass access controls, or use Meta's official API
- A capped snapshot can still be useful for research, but capped observations are not allowed to mutate a monitoring baseline
FAQ
Why is my first monitoring Dataset empty?
changes needs two observations to detect a change. The first complete run
creates the baseline and writes a clear explanation to the run summary. Use
all_current for instant results or all to emit the baseline as NEW events.
Why was my baseline not updated?
The observation was likely failed, capped, explicitly partial, or suspiciously
smaller than the previous snapshot. This is intentional protection against
false STOPPED alerts. Increase maxAdsPerCompetitor or inspect the child run.
How often should I schedule it?
Daily is a practical default. Higher frequency costs more and does not guarantee that Meta exposes updates sooner.
Can I monitor multiple clients?
Yes. Use a separate monitorId for each client or independent monitor. You can
include up to 100 competitors in one input, subject to your maximum run charge.
Does it download creative files?
No. It stores normalized fields, URLs, and fingerprints rather than creative binaries.
Start now
Run the prefilled snapshot to see the output. Then replace Nike with your exact
competitor, switch to changes, save the input as a Task, and schedule it daily.