# Facebook Ad Library Scraper - Meta Ads Monitor (`leadproof/facebook-ads-monitor`) Actor

Scrape active ads from the Meta (Facebook) Ad Library by advertiser or keyword. Export ad copy, creative URLs and destinations, and track creative changes across runs to monitor competitor ads. No Facebook login required.

- **URL**: https://apify.com/leadproof/facebook-ads-monitor.md
- **Developed by:** [Lead Proof](https://apify.com/leadproof) (community)
- **Categories:** Social media, Marketing, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 ad observations

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Facebook Ads Monitor

Collect active ads from Meta Ad Library by advertiser Page ID or keyword, export their creative content, and compare observations across runs. No Facebook login or customer cookies are required.

Use it for competitor ad research, creative reviews, and recurring advertiser monitoring. Results include ad copy, image and video URLs, carousel cards, calls to action, destination URLs, advertiser details, and source links.

### Quick start

1. Enter an advertiser's numeric Page ID or one or more keywords.
2. Choose a country and the maximum number of ads per target.
3. Run the Actor and export the Dataset as JSON, CSV, or Excel.

For recurring monitoring, reuse a `monitorKey` and the same country. You can schedule the same input in Apify. Omit `monitorKey` for one-off collection.

```json
{
  "pageIds": ["15087023444"],
  "country": "US",
  "maxAdsPerTarget": 25,
  "maxTargetSeconds": 60,
  "maxRunSeconds": 240,
  "monitorKey": "my-competitors"
}
```

Find a Page ID in the `view_all_page_id` parameter of an advertiser's Meta Ad Library URL. Keyword searches use a `keywords` array. When using keywords alone in the input form, clear the prefilled Page ID to avoid checking both.

### Pricing

**$1.50 per 1,000 returned ad observations + $0.03 per Page ID or keyword checked.** Compute and Apify proxy usage are included. Prices are the same across Apify plan tiers.

| Example | Total |
| --- | ---: |
| 1 target, 25 returned ads | $0.0675 |
| 1 target, 1,000 returned ads | $1.53 |
| 10 targets, 100 returned ads each | $1.80 |

Each run charges for its returned observations, including unchanged ads. Comparison is included. A checked target incurs its check fee even if the search returns no ads or is blocked; its outcome is recorded in `SUMMARY`. Duplicate input targets are checked once. Targets skipped because of time or spending limits incur no check fee.

Set **Maximum charge per run** to control spending. At least $0.0315 is required to begin a target. Collection stops when the remaining budget cannot pay for another target or observation. Results limited by spending are explicitly marked partial.

### Input

| Field | Purpose | Default |
| --- | --- | --- |
| `pageIds` | Advertiser Page IDs with exact advertiser filtering | Nike in the example form |
| `keywords` | Keyword searches using Meta's relevance matching | None |
| `country` | Uppercase two-letter country code, or `ALL` | `US` |
| `maxAdsPerTarget` | Maximum unique ads returned per target | 25 |
| `maxTargetSeconds` | Collection time allowed per target | 60 seconds |
| `maxRunSeconds` | Collection time budget for the whole run | 240 seconds |
| `maxScrolls` | Pagination attempts per target | 30 |
| `monitorKey` | Optional name used to compare recurring runs | None |
| `proxyConfiguration` | Optional proxy configuration | Apify residential in the selected country |

Provide 1-100 unique targets. These are input ceilings, not guarantees that all requested targets or ads will fit within a run. For larger collections, increase the per-target and overall time budgets as well as the result limit. Storage and shutdown can take additional time, so set an Apify run timeout too.

Use different monitor names for different clients. Country and target changes use separate history scopes. Concurrent runs sharing a monitor name are rejected with `MONITOR_BUSY`; start the next run after the previous one finishes.

### Output

Each Dataset row can include:

- Ad ID, Meta Ad Library URL, advertiser ID, name, and profile URL.
- Body text, title, description, caption, CTA, and destination URL.
- Image/video URLs and individual carousel cards.
- Source activity, source dates, publisher platforms, and observation time.
- Content quality and partial-coverage indicators.
- Monitoring labels and previous observation timestamps when a monitor is enabled.

Fields depend on what Meta exposes. Media URLs are provided as links and can expire. Downloading or permanently archiving media files is not included; `archiveMedia: true` is rejected in paid runs.

#### Understanding monitoring labels

| Label | Meaning |
| --- | --- |
| `first_observed` | First usable observation in this monitor, not the campaign launch time. |
| `changed` | Observed creative content differs from the previous usable observation. |
| `unchanged` | The normalized creative content matches. |
| `unverified` | Missing content or unresolved templates prevent reliable comparison. The previous good baseline is preserved. |

Dynamic product ads can display different variants between visits. Resolved product details may be in `cards` while the parent contains a template. CDN signature changes and carousel ordering alone do not trigger a creative change.

Missing ads are never assumed to have ended. `activeChanged` requires two explicit source activity values. Failed, empty, or partial collection does not erase earlier observations.

### Coverage and limitations

- Only active-ad searches are supported. This Actor does not provide spend, conversions, impressions, targeting, or exhaustive ad history.
- Keyword relevance follows Meta's results; the search phrase need not appear in every ad.
- Results may be partial because of result/time/spending limits, source visibility, stalled pagination, or access failures. Check each row's coverage fields and the run's `SUMMARY`.
- `source_exhausted` means the observed search connection reported no next page, not that every ad Meta could serve has been retrieved.
- Persistent blocks, login walls, or access challenges stop collection. A blocked run with zero returned ads fails. Check fees may still apply to targets already checked.
- Monitoring history supports up to 100,000 ad IDs per target scope. Interruptions can redeliver rows; downstream automations should deduplicate by monitor, scope, ad ID, and run.
- Start a new run instead of resurrecting a previously charged run. Charged-run resurrection is rejected to avoid repeating charges.
- Persistent storage follows Apify retention and billing rules. External proxy services supplied by a customer may bill separately.

Launch validation included a 1,000-ad collection, multi-country and keyword checks, repeated observations, concurrent-monitor rejection, and real spending-limit tests. These bounded tests do not establish a long-term success rate or guarantee future source availability.

### Run diagnostics

The default key-value store contains `SUMMARY`, with each target's outcome, coverage reason, timings, row counts, and applied billing events. Use it to distinguish an empty search from a skipped or blocked target.

### Support

Open an issue on this Actor's Apify page with your run ID, input, and expected result. Remove private credentials or confidential information before sharing.

# Actor input Schema

## `pageIds` (type: `array`):

Numeric view\_all\_page\_id values from Meta Ad Library URLs. Exact advertiser filtering.

## `keywords` (type: `array`):

Optional keyword searches. Results follow Meta's matching; keyword text is not guaranteed to occur in every ad.

## `country` (type: `string`):

Uppercase two-letter country code, or ALL.

## `maxAdsPerTarget` (type: `integer`):

Maximum unique ads returned for each Page ID or keyword. Reaching this cap means coverage is partial.

## `maxRunSeconds` (type: `integer`):

Collection time budget. Allow additional time for storage and shutdown. Set Maximum charge per run separately to bound spending.

## `maxTargetSeconds` (type: `integer`):

Maximum collection time allocated to each advertiser or keyword. Default 60 seconds; large targets can explicitly request up to 900 seconds within the run budget.

## `maxScrolls` (type: `integer`):

Maximum pagination scroll attempts for each target.

## `monitorKey` (type: `string`):

Reuse the same name for scheduled runs. Different clients should use different names. Omit for one-off collection. 1-64 letters, digits, - or \_. Concurrent runs with this name are rejected.

## `proxyConfiguration` (type: `object`):

Defaults to Apify residential proxy in the selected country (US for ALL), included in the pay-per-event price. External proxy services you supply can bill you separately.

## Actor input object example

```json
{
  "pageIds": [
    "15087023444"
  ],
  "country": "US",
  "maxAdsPerTarget": 25,
  "maxRunSeconds": 240,
  "maxTargetSeconds": 60,
  "maxScrolls": 30
}
```

# Actor output Schema

## `ads` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {
    "pageIds": [
        "15087023444"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("leadproof/facebook-ads-monitor").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 = { "pageIds": ["15087023444"] }

# Run the Actor and wait for it to finish
run = client.actor("leadproof/facebook-ads-monitor").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 '{
  "pageIds": [
    "15087023444"
  ]
}' |
apify call leadproof/facebook-ads-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,leadproof/facebook-ads-monitor"
        }
    }
}
```

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/jhutQ2dS5Pe95Y9fl/builds/6tLHs3UiwGtW9jhLj/openapi.json
