# Meta Ads Offer & Landing Page Tracker (`vgvianna/meta-ads-offer-landing-page-tracker`) Actor

Monitor active Meta ads and reliably detect observed changes in their landing-page offers over time.

- **URL**: https://apify.com/vgvianna/meta-ads-offer-landing-page-tracker.md
- **Developed by:** [Victor Gabriel Vianna](https://apify.com/vgvianna) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $35.00 / 1,000 competitor processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Meta Ads Offer & Landing Page Tracker

Monitor active ads from Facebook Pages or advertiser-scoped Meta Ad Library URLs and observe their associated landing pages over time. It is for DTC/e-commerce teams, agencies, media buyers, and competitive-intelligence workflows that need reliable **observed changes**, not a generic Ad Library scraper.

The first compatible run creates a baseline and emits snapshots, never market-change events. Later compatible runs emit snapshots and/or changes according to `outputMode`. A change records an observation, not global commercial truth: A/B tests, country context, personalisation, blocking, and incomplete coverage can affect what is seen.

### Inputs

- `competitors`: 1–50 Facebook Page URLs or advertiser-scoped Ad Library URLs. Labels are presentation-only, not identity.
- `monitorName`: stable state namespace for the monitor.
- `countryCode`, `maxAdsPerCompetitor`, `trackLandingPages`, `maxLandingPages`, `outputMode`, `landingPageTimeoutSecs`, and `browserFallback` have conservative defaults in the Input tab.

The Store health-check prefill is one public Nike Page with monitor name `store-health-check-nike`, `countryCode: ALL`, and both per-competitor and landing-page limits set to 1. It is an example for the Console only; the API defaults remain suitable for normal monitoring calls.

The supported events are `NEW_AD`, `AD_COPY_CHANGED`, `LANDING_URL_CHANGED`, `PRICE_CHANGED`, `ORIGINAL_PRICE_CHANGED`, `DISCOUNT_CHANGED`, and `PRODUCT_CHANGED`. `AD_STOPPED`, `PRODUCT_REMOVED`, ROAS/profitability, winning-ad scoring, creative AI analysis, and universal scraping are deliberately not supported.

Landing tracking removes known tracking parameters from identity, preserves functional parameters, fetches shared canonical landings once when known, and uses JSON-LD before structured and OpenGraph metadata. Failed, blocked, or ambiguous extraction never overwrites a confirmed commercial value. Consumers should de-duplicate retries using `eventId`; a later legitimate recurrence of the same before/after transition receives a new ID.

### Output and pricing

The default Dataset contains `SNAPSHOT` and `CHANGE` records. `RUN_SUMMARY` in the default Key-Value Store reports coverage, warnings, child runs, landing statuses, and charge counters. Use Apify schedules and Dataset/webhook integrations for automation.

The configured PPE prices are US$0.05 per successfully fetched, contract-validated, normalized competitor and US$0.01 per unique conclusively checked landing (`FOUND`, `NOT_PRESENT`, `AMBIGUOUS`, or documented `NOT_APPLICABLE`). The synthetic `apify-actor-start` event is US$0.00005 per charged start (the count depends on allocated memory). Platform usage for this Actor is included in PPE. Failed, blocked, and extraction-failed landings are not charged; failed child runs, changes, and Dataset items are not separately charged by this Actor.

The upstream Facebook Ad Library Actor is a separate run in the user's account and adds its own current cost. Its `limitPerSource` may return and bill up to 30 additional records. Every child call receives a finite ceiling that accounts for that documented over-return. If a finite parent ceiling cannot accommodate the requested child coverage, the tracker reduces `limitPerSource` and reports `UPSTREAM_BUDGET_LIMIT_REACHED`. Parent and child spending limits are still separate Apify run limits.

This Actor is configured as PAY\_PER\_EVENT with included platform usage, the two custom events above, the synthetic start event, and no `apify-default-dataset-item` event. This repository's `.actor/pay_per_event.json` mirrors that saved Console configuration; deploying source does not itself change pricing.

This Actor is not affiliated with, endorsed by, or an official product of Meta.

### Limitations

This Actor does not scrape Meta directly, has no residential proxy, dashboard, native Slack/email integration, visual analysis, or complete historical Ad Library coverage. It blocks private/internal HTTP(S) targets and caps redirects, body size, and timeouts. Browser fallback is intentionally isolated to the final landing host, so sites that require cross-domain assets can remain incomplete rather than weaken URL safety. Do not overlap runs that use the same `monitorName`; concurrent observations can race on shared state.

# Actor input Schema

## `competitors` (type: `array`):

One to fifty Facebook Page URLs or advertiser-scoped Meta Ad Library URLs.

## `monitorName` (type: `string`):

Stable name used to locate the monitor state.

## `countryCode` (type: `string`):

ALL or an ISO-2 country code.

## `maxAdsPerCompetitor` (type: `integer`):

From 1 to 1000. Reaching the cap is reported as incomplete coverage.

## `trackLandingPages` (type: `boolean`):

Enable conservative product and offer observation for destination pages.

## `maxLandingPages` (type: `integer`):

From 1 to 1000 after global URL deduplication.

## `outputMode` (type: `string`):

Return current snapshots with changes, or only changes after the baseline.

## `landingPageTimeoutSecs` (type: `integer`):

Per landing request timeout, from 10 to 60 seconds.

## `browserFallback` (type: `boolean`):

Use one Chromium fallback when HTTP extraction is insufficient.

## Actor input object example

```json
{
  "competitors": [
    {
      "url": "https://www.facebook.com/nike",
      "label": "Nike"
    }
  ],
  "monitorName": "store-health-check-nike",
  "countryCode": "ALL",
  "maxAdsPerCompetitor": 1,
  "trackLandingPages": true,
  "maxLandingPages": 1,
  "outputMode": "current_and_changes",
  "landingPageTimeoutSecs": 30,
  "browserFallback": true
}
```

# Actor output Schema

## `records` (type: `string`):

Default Dataset records. De-duplicate CHANGE records using eventId.

## `runSummary` (type: `string`):

RUN\_SUMMARY from the default Key-Value Store, including coverage, warnings, and charge counters.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "competitors": [
        {
            "url": "https://www.facebook.com/nike",
            "label": "Nike"
        }
    ],
    "monitorName": "store-health-check-nike",
    "countryCode": "ALL",
    "maxAdsPerCompetitor": 1,
    "trackLandingPages": true,
    "maxLandingPages": 1,
    "outputMode": "current_and_changes",
    "landingPageTimeoutSecs": 30,
    "browserFallback": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("vgvianna/meta-ads-offer-landing-page-tracker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "competitors": [{
            "url": "https://www.facebook.com/nike",
            "label": "Nike",
        }],
    "monitorName": "store-health-check-nike",
    "countryCode": "ALL",
    "maxAdsPerCompetitor": 1,
    "trackLandingPages": True,
    "maxLandingPages": 1,
    "outputMode": "current_and_changes",
    "landingPageTimeoutSecs": 30,
    "browserFallback": True,
}

# Run the Actor and wait for it to finish
run = client.actor("vgvianna/meta-ads-offer-landing-page-tracker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "competitors": [
    {
      "url": "https://www.facebook.com/nike",
      "label": "Nike"
    }
  ],
  "monitorName": "store-health-check-nike",
  "countryCode": "ALL",
  "maxAdsPerCompetitor": 1,
  "trackLandingPages": true,
  "maxLandingPages": 1,
  "outputMode": "current_and_changes",
  "landingPageTimeoutSecs": 30,
  "browserFallback": true
}' |
apify call vgvianna/meta-ads-offer-landing-page-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vgvianna/meta-ads-offer-landing-page-tracker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/yhgZAYNoVXrPmpoZ5/builds/Sz1KktIkCs1IwP4pZ/openapi.json
