# META ADS LYBRRYA SRAPPER (Cost-Optimized) (`defensible_jadeite/meta-ads-library-scraper`) Actor

Low-cost Meta Ads Library scraper for competitor research. Uses the official Meta Ads Archive API first with no proxy, exports public ad links, page names, ad copy, dates, platforms, spend and impression fields, and supports n8n or spreadsheet workflows.

- **URL**: https://apify.com/defensible\_jadeite/meta-ads-library-scraper.md
- **Developed by:** [MOHAMED CHAREUF](https://apify.com/defensible_jadeite) (community)
- **Categories:** E-commerce
- **Stats:** 4 total users, 1 monthly users, 70.5% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Meta Ads Library Scraper - Low-Cost API

Search public Meta Ads Archive data for competitor research and export clean ad records to an Apify dataset. This Actor is built for cost-sensitive research workflows, n8n automations, and spreadsheet analysis.

The default path uses the official Meta Ads Archive Graph API without Apify Proxy. Browser mode is kept only as an optional fallback/debug path.

This Actor is unofficial and is not affiliated with Meta, Facebook, Instagram, or Apify. It uses public Meta Ad Library / Ads Archive data only. It does not automate login, solve CAPTCHA, bypass access restrictions, or collect private user data.

### What you can do

- Search public ad archive records by keyword.
- Filter by reached countries, active status, launch date window, ad language, media type, and optional CTA text.
- Export ad IDs, public ad links, advertiser page, ad copy, headline, launch date, platform, spend and impression fields when Meta returns them.
- Run API-only mode for zero proxy usage.
- Integrate with n8n, Make, Zapier, Google Sheets, or the Apify API.

### Lowest-cost mode

Use:

```json
{
  "forceMode": "api",
  "maxResults": 1000,
  "apiPageSize": 100
}
````

API mode uses no Apify Proxy. The main cost is Apify compute time. Small test runs always have startup overhead, so measure price on larger batches such as 500 to 1000 results.

### Snapshot enrichment

Turn on `enableSnapshotEnrichment` only when you need cleaner CTA, headline, media type, carousel count, or destination URL from each public `ad_snapshot_url`.

Cost controls:

- The Actor filters and deduplicates API results first, then enriches only rows that will be saved.
- One shared Playwright browser is reused for the run.
- Snapshot concurrency is capped at `3`.
- `maxSnapshotEnrichments` limits how many saved ads are opened in Playwright.

Example:

```json
{
  "enableSnapshotEnrichment": true,
  "snapshotConcurrency": 3,
  "maxSnapshotEnrichments": 100
}
```

For the absolute lowest cost, keep `enableSnapshotEnrichment` off.

### Requirements

You need a Meta Ads Library API access token with Ads Archive access. Temporary Graph API Explorer user tokens can work for testing but expire. For production, use a long-lived Business token after Meta approval.

For private runs, save the token as a secret environment variable:

```text
META_TOKEN
```

For public users, paste the token into the `Meta access token` input field. The field is marked as secret in the Apify input UI.

### Input

Example:

```json
{
  "searchTerms": "SHOP NOW",
  "countries": ["DZ", "FR"],
  "maxResults": 1000,
  "activeOnly": true,
  "activeLastDays": 60,
  "apiPageSize": 100,
  "maxApiPages": 25,
  "searchType": "KEYWORD_UNORDERED",
  "ctaFilter": "SHOP NOW",
  "language": "ar",
  "mediaType": "VIDEO",
  "requireCtaMatch": true,
  "maxStrictCtaNoMatchPages": 3,
  "enableSnapshotEnrichment": false,
  "forceMode": "api",
  "metaAccessToken": "YOUR_META_ADS_LIBRARY_API_TOKEN"
}
```

#### Main fields

- `searchTerms` - Keyword or phrase to search.
- `countries` - Country codes such as `DZ`, `FR`, `MA`, `US`, or `ALL`.
- `maxResults` - Maximum ads to save.
- `activeOnly` - Requests currently active ads from Meta.
- `activeLastDays` - Filters launch date by the last N days.
- `adDeliveryDateMin` / `adDeliveryDateMax` - Exact date window in `YYYY-MM-DD`.
- `apiPageSize` / `maxApiPages` - Batch size and safety cap for API pagination. Lower `maxApiPages` when strict filters return no rows.
- `ctaFilter` - Optional CTA hints such as `SHOP NOW, ORDER NOW` or `SHOP NOW AND ORDER NOW`.
- `language` / `languages` - Optional Meta language filter. Use `ar` or `["ar"]` for Arabic, `en` for English, `fr` for French. Leave empty to keep all languages.
- `mediaType` - Optional Meta API `media_type` search filter. Use `ALL`, `IMAGE`, `VIDEO`, `MEME`, or `NONE`. This is applied before pagination and can reduce compute for video/image-only research.
- `requireCtaMatch` - Keep on when you need only the selected CTA. The Actor checks returned CTA fields first, then exact creative text fallback when Meta does not expose the CTA field.
- `maxStrictCtaNoMatchPages` - Stops early when strict CTA matching sees no matching CTA for several consecutive API pages.
- `enableSnapshotEnrichment` - Opens saved public snapshot pages with Playwright to extract cleaner `headline`, `cta_text`, `media_type`, `carousel_count`, and `destination_url`.
- `maxSnapshotEnrichments` - Caps snapshot parsing so test runs do not become expensive.
- `forceMode` - Use `api` for lowest cost, `auto` for API then browser fallback, `browser` only for debugging.
- `metaAccessToken` - Optional secret input token. If omitted, the Actor uses `META_TOKEN`.

### Output

The default dataset includes the public fields returned by Meta plus helpful normalized links:

- `id`
- `adLibraryUrl`
- `ad_snapshot_url`
- `page_id`
- `page_name`
- `ad_creative_bodies`
- `ad_creative_link_titles`
- `ad_creative_link_descriptions`
- `headline`
- `cta_text`
- `media_type`
- `carousel_count`
- `destination_url`
- `snapshot_enrichment`
- `ad_delivery_start_time`
- `ad_delivery_stop_time`
- `publisher_platforms`
- `languages`
- `impressions`
- `spend`
- `currency`
- `searchTermsUsed`
- `relaxedSearch`

The Output tab uses an overview table for the most useful spreadsheet columns. Full JSON is still available for export.

### n8n API example

Use the synchronous endpoint when you want n8n to receive dataset items directly:

```text
POST https://api.apify.com/v2/acts/defensible_jadeite~meta-ads-library-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN&maxTotalChargeUsd=1
```

Public API actor ID:

```text
defensible_jadeite~meta-ads-library-scraper
```

The public Store URL uses a slash:

```text
https://apify.com/defensible_jadeite/meta-ads-library-scraper
```

Do not paste `defensible_jadeite/meta-ads-library-scraper` into the `/acts/...` API path. Apify API actor identifiers must use either the raw Actor ID or the tilde form. The slash form returns `404 Actor wasn't found`.

Correct n8n expression:

```text
https://api.apify.com/v2/acts/{{ $('YOUR KEYS').item.json.APIFY_ACTOR_ID }}/run-sync-get-dataset-items?token={{ $('YOUR KEYS').item.json.APIFY_API_KEY }}&maxTotalChargeUsd=1
```

Set the keys node values to:

```json
{
  "APIFY_ACTOR_ID": "defensible_jadeite~meta-ads-library-scraper",
  "APIFY_API_KEY": "YOUR_APIFY_API_TOKEN",
  "META_ACCESS_TOKEN": "YOUR_META_ADS_LIBRARY_API_TOKEN"
}
```

Headers:

```json
{
  "Content-Type": "application/json"
}
```

Body:

```json
{
  "searchTerms": "SHOP NOW",
  "countries": ["DZ"],
  "maxResults": 1000,
  "forceMode": "api",
  "activeOnly": true,
  "activeLastDays": 60,
  "apiPageSize": 100,
  "maxApiPages": 25,
  "language": "ar",
  "languages": ["ar"],
  "mediaType": "VIDEO",
  "ctaFilter": "SHOP NOW",
  "requireCtaMatch": true,
  "maxStrictCtaNoMatchPages": 3,
  "enableSnapshotEnrichment": false,
  "failOnNoResults": true,
  "metaAccessToken": "{{ $('YOUR KEYS').item.json.META_ACCESS_TOKEN }}"
}
```

For a small n8n test, set `maxResults` to `5`. If the HTTP Request node returns `Actor wasn't found`, the `APIFY_ACTOR_ID` value is wrong. If it returns `401` or `403`, the Apify API token is wrong. If the Meta API returns a permission error, update the Meta Ads Library API token.

If a run finishes with no ads, open the run key-value store and inspect `RUN_SUMMARY`. It explains whether the Actor saw a Meta API/token error, strict filters, or a real no-result search. By default, API errors and empty results fail the run so n8n does not continue with an empty sheet by mistake.

### Important limitations

- Meta can limit which commercial ads are available through the official API by region and policy category.
- If the official API returns zero records for a keyword, try a broader keyword, more countries, or `activeOnly: false`.
- `language` uses Meta's official `languages` search parameter. For Arabic, the Actor also checks for Arabic script when Meta does not return a language field.
- `mediaType` uses Meta's official `media_type` search parameter. Supported values are `ALL`, `IMAGE`, `VIDEO`, `MEME`, and `NONE`.
- `ctaFilter` is strict when `requireCtaMatch` is true. Separate multiple CTAs with commas or `AND`, for example `SHOP NOW, ORDER NOW` or `SHOP NOW AND ORDER NOW`.
- Meta does not expose a CTA field for every ad. When the CTA field is missing, the Actor uses exact creative text fallback and records `ctaFilterMatchSource` so you can see how the row matched.
- Snapshot enrichment can extract CTA from the public snapshot page, but it costs extra compute because it opens pages in Playwright.
- If strict CTA matching returns no rows, the Actor stops after `maxStrictCtaNoMatchPages` no-match pages instead of scanning the full result set.
- Browser fallback costs more because it uses Playwright and Apify Proxy.

### Troubleshooting

`Missing META_TOKEN`

Add a Meta token in `metaAccessToken` or set the `META_TOKEN` secret environment variable.

`Invalid Meta token input: received an Apify ENCRYPTED_VALUE placeholder`

Do not copy the hidden token value from an old Apify run input. Paste a fresh Meta Ads Library API token into `metaAccessToken`, or save it as the `META_TOKEN` Actor secret.

`Application does not have permission for this action`

Your token has not been approved for Ads Archive API access yet. Complete the official Meta flow at:

```text
https://www.facebook.com/ads/library/api/
```

Zero results but no error

The keyword, date, country, language, or active-only filter may be too strict. Start with `activeOnly: false`, remove `ctaFilter`, clear `language`, test a broad keyword, and check the `RUN_SUMMARY` key-value-store record.

High cost

Use `forceMode: "api"` and keep `enableSnapshotEnrichment: false` for the cheapest runs. Avoid `auto` or `browser` unless you explicitly want browser fallback. If snapshot enrichment is needed, lower `maxSnapshotEnrichments`.

# Actor input Schema

## `searchTerms` (type: `string`):

Keywords to search in ads

## `countries` (type: `array`):

Country codes e.g. \['DZ', 'FR', 'MA']

## `maxResults` (type: `integer`):

Maximum number of unique ads to save.

## `activeOnly` (type: `boolean`):

Ask the official Meta API for active ads only before results are returned.

## `activeLastDays` (type: `integer`):

Pre-filter by delivery start date before fetching results. Example: 60 means ads launched in the last 60 days.

## `adDeliveryDateMin` (type: `string`):

Optional exact Meta API ad\_delivery\_date\_min in YYYY-MM-DD format. Overrides Active in last N days when provided.

## `adDeliveryDateMax` (type: `string`):

Optional exact Meta API ad\_delivery\_date\_max in YYYY-MM-DD format.

## `apiPageSize` (type: `integer`):

How many ads to request per Meta API page. Meta currently caps this conservatively, so 100 is the default.

## `maxApiPages` (type: `integer`):

Safety cap for API pagination. Lower values reduce cost when filters are too strict.

## `searchType` (type: `string`):

KEYWORD\_UNORDERED returns more results. KEYWORD\_EXACT\_PHRASE is stricter and may return very few ads.

## `ctaFilter` (type: `string`):

CTA values such as SHOP NOW, ORDER NOW, or LEARN MORE. Separate multiple CTAs with commas or AND. With Require CTA match enabled, rows are kept when the returned CTA field or exact creative text fallback matches.

## `language` (type: `string`):

Optional ad language code. Use ar for Arabic, en for English, fr for French. Leave empty to keep all languages.

## `mediaType` (type: `string`):

Optional Meta API media\_type search filter. Use ALL, IMAGE, VIDEO, MEME, or NONE. This is sent to Meta before pagination to reduce API pages and compute.

## `languages` (type: `array`):

Optional ISO 639 language codes for Meta's languages API parameter. Example: \["ar"] for Arabic or \["ar", "fr"] for both.

## `requireCtaMatch` (type: `boolean`):

When enabled, discard ads before saving if returned API CTA fields match the selected CTA filter. Keep disabled when using snapshot CTA enrichment or n8n CTA status columns.

## `maxStrictCtaNoMatchPages` (type: `integer`):

When strict CTA matching is enabled, stop early after this many consecutive API pages have no matching CTA.

## `metaAccessToken` (type: `string`):

Optional temporary Meta Graph API token. If empty, the actor uses the META\_TOKEN secret from Actor settings. Paste a real token only; do not copy ENCRYPTED\_VALUE placeholders from old Apify run inputs.

## `enableSnapshotEnrichment` (type: `boolean`):

Open each saved ad snapshot page with Playwright to extract cleaner headline, CTA, media type, carousel count, and destination URL. Leave off for the lowest cost.

## `snapshotConcurrency` (type: `integer`):

Maximum snapshot pages opened at the same time. Capped at 3 to control compute and bandwidth.

## `snapshotBatchSize` (type: `integer`):

How many snapshot-enriched ads to process before saving to the dataset. Smaller batches prevent empty datasets if long snapshot runs time out.

## `maxSnapshotEnrichments` (type: `integer`):

Maximum number of saved ads to enrich with snapshot page parsing. Lower this when testing to avoid extra compute.

## `snapshotTimeLimitSecs` (type: `integer`):

Maximum time spent opening snapshot pages for CTA and landing-page extraction. When reached, remaining API results are still saved without snapshot enrichment so the Actor does not time out.

## `anthropicApiKey` (type: `string`):

Optional. Used only when semantic selectors and text scan cannot find CTA text. Leave empty to avoid Vision LLM cost.

## `relaxSearchOnNoResults` (type: `boolean`):

When enabled, a multi-word keyword such as 'pillow sleep' is retried with the first word if the exact active search returns 0 ads. Useful for n8n sheets so strict phrases do not produce empty datasets.

## `failOnNoResults` (type: `boolean`):

When enabled, the Actor fails instead of silently succeeding with an empty dataset. Recommended for n8n so token/API/filter problems are visible.

## `forceMode` (type: `string`):

api = lowest cost and no proxy. auto = API first, then DATACENTER browser fallback. browser = browser only for debugging.

## Actor input object example

```json
{
  "searchTerms": "SHOP NOW",
  "countries": [
    "DZ"
  ],
  "maxResults": 200,
  "activeOnly": true,
  "activeLastDays": 60,
  "apiPageSize": 100,
  "maxApiPages": 25,
  "searchType": "KEYWORD_UNORDERED",
  "language": "ar",
  "mediaType": "ALL",
  "languages": [],
  "requireCtaMatch": false,
  "maxStrictCtaNoMatchPages": 3,
  "enableSnapshotEnrichment": false,
  "snapshotConcurrency": 3,
  "snapshotBatchSize": 10,
  "maxSnapshotEnrichments": 100,
  "snapshotTimeLimitSecs": 480,
  "relaxSearchOnNoResults": true,
  "failOnNoResults": true,
  "forceMode": "api"
}
```

# Actor output Schema

## `results` (type: `string`):

Clean ad records saved by the Actor. Use this URL to download JSON, CSV, Excel, or connect the results to n8n.

# 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 = {
    "searchTerms": "SHOP NOW",
    "language": "ar"
};

// Run the Actor and wait for it to finish
const run = await client.actor("defensible_jadeite/meta-ads-library-scraper").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 = {
    "searchTerms": "SHOP NOW",
    "language": "ar",
}

# Run the Actor and wait for it to finish
run = client.actor("defensible_jadeite/meta-ads-library-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "searchTerms": "SHOP NOW",
  "language": "ar"
}' |
apify call defensible_jadeite/meta-ads-library-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=defensible_jadeite/meta-ads-library-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "META ADS LYBRRYA SRAPPER (Cost-Optimized)",
        "description": "Low-cost Meta Ads Library scraper for competitor research. Uses the official Meta Ads Archive API first with no proxy, exports public ad links, page names, ad copy, dates, platforms, spend and impression fields, and supports n8n or spreadsheet workflows.",
        "version": "1.0",
        "x-build-id": "lwDCtluG8QLVxAazy"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/defensible_jadeite~meta-ads-library-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-defensible_jadeite-meta-ads-library-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/defensible_jadeite~meta-ads-library-scraper/runs": {
            "post": {
                "operationId": "runs-sync-defensible_jadeite-meta-ads-library-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/defensible_jadeite~meta-ads-library-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-defensible_jadeite-meta-ads-library-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchTerms": {
                        "title": "Search terms",
                        "type": "string",
                        "description": "Keywords to search in ads"
                    },
                    "countries": {
                        "title": "Countries",
                        "type": "array",
                        "description": "Country codes e.g. ['DZ', 'FR', 'MA']",
                        "default": [
                            "DZ"
                        ]
                    },
                    "maxResults": {
                        "title": "Max results",
                        "minimum": 1,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Maximum number of unique ads to save.",
                        "default": 200
                    },
                    "activeOnly": {
                        "title": "Active ads only",
                        "type": "boolean",
                        "description": "Ask the official Meta API for active ads only before results are returned.",
                        "default": true
                    },
                    "activeLastDays": {
                        "title": "Active in last N days",
                        "minimum": 1,
                        "maximum": 365,
                        "type": "integer",
                        "description": "Pre-filter by delivery start date before fetching results. Example: 60 means ads launched in the last 60 days.",
                        "default": 60
                    },
                    "adDeliveryDateMin": {
                        "title": "Delivery date min",
                        "type": "string",
                        "description": "Optional exact Meta API ad_delivery_date_min in YYYY-MM-DD format. Overrides Active in last N days when provided."
                    },
                    "adDeliveryDateMax": {
                        "title": "Delivery date max",
                        "type": "string",
                        "description": "Optional exact Meta API ad_delivery_date_max in YYYY-MM-DD format."
                    },
                    "apiPageSize": {
                        "title": "API page size",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "How many ads to request per Meta API page. Meta currently caps this conservatively, so 100 is the default.",
                        "default": 100
                    },
                    "maxApiPages": {
                        "title": "Max API pages",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Safety cap for API pagination. Lower values reduce cost when filters are too strict.",
                        "default": 25
                    },
                    "searchType": {
                        "title": "Search type",
                        "enum": [
                            "KEYWORD_UNORDERED",
                            "KEYWORD_EXACT_PHRASE"
                        ],
                        "type": "string",
                        "description": "KEYWORD_UNORDERED returns more results. KEYWORD_EXACT_PHRASE is stricter and may return very few ads.",
                        "default": "KEYWORD_UNORDERED"
                    },
                    "ctaFilter": {
                        "title": "Call to action filter",
                        "type": "string",
                        "description": "CTA values such as SHOP NOW, ORDER NOW, or LEARN MORE. Separate multiple CTAs with commas or AND. With Require CTA match enabled, rows are kept when the returned CTA field or exact creative text fallback matches."
                    },
                    "language": {
                        "title": "Language filter",
                        "type": "string",
                        "description": "Optional ad language code. Use ar for Arabic, en for English, fr for French. Leave empty to keep all languages."
                    },
                    "mediaType": {
                        "title": "Media type filter",
                        "enum": [
                            "ALL",
                            "IMAGE",
                            "VIDEO",
                            "MEME",
                            "NONE"
                        ],
                        "type": "string",
                        "description": "Optional Meta API media_type search filter. Use ALL, IMAGE, VIDEO, MEME, or NONE. This is sent to Meta before pagination to reduce API pages and compute.",
                        "default": "ALL"
                    },
                    "languages": {
                        "title": "Language filters advanced",
                        "type": "array",
                        "description": "Optional ISO 639 language codes for Meta's languages API parameter. Example: [\"ar\"] for Arabic or [\"ar\", \"fr\"] for both.",
                        "default": []
                    },
                    "requireCtaMatch": {
                        "title": "Require CTA match",
                        "type": "boolean",
                        "description": "When enabled, discard ads before saving if returned API CTA fields match the selected CTA filter. Keep disabled when using snapshot CTA enrichment or n8n CTA status columns.",
                        "default": false
                    },
                    "maxStrictCtaNoMatchPages": {
                        "title": "Max CTA no-match pages",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "When strict CTA matching is enabled, stop early after this many consecutive API pages have no matching CTA.",
                        "default": 3
                    },
                    "metaAccessToken": {
                        "title": "Meta access token",
                        "type": "string",
                        "description": "Optional temporary Meta Graph API token. If empty, the actor uses the META_TOKEN secret from Actor settings. Paste a real token only; do not copy ENCRYPTED_VALUE placeholders from old Apify run inputs."
                    },
                    "enableSnapshotEnrichment": {
                        "title": "Enrich snapshot pages",
                        "type": "boolean",
                        "description": "Open each saved ad snapshot page with Playwright to extract cleaner headline, CTA, media type, carousel count, and destination URL. Leave off for the lowest cost.",
                        "default": false
                    },
                    "snapshotConcurrency": {
                        "title": "Snapshot concurrency",
                        "minimum": 1,
                        "maximum": 3,
                        "type": "integer",
                        "description": "Maximum snapshot pages opened at the same time. Capped at 3 to control compute and bandwidth.",
                        "default": 3
                    },
                    "snapshotBatchSize": {
                        "title": "Snapshot save batch size",
                        "minimum": 1,
                        "maximum": 25,
                        "type": "integer",
                        "description": "How many snapshot-enriched ads to process before saving to the dataset. Smaller batches prevent empty datasets if long snapshot runs time out.",
                        "default": 10
                    },
                    "maxSnapshotEnrichments": {
                        "title": "Max enriched snapshots",
                        "minimum": 0,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Maximum number of saved ads to enrich with snapshot page parsing. Lower this when testing to avoid extra compute.",
                        "default": 100
                    },
                    "snapshotTimeLimitSecs": {
                        "title": "Snapshot time limit seconds",
                        "minimum": 0,
                        "maximum": 3600,
                        "type": "integer",
                        "description": "Maximum time spent opening snapshot pages for CTA and landing-page extraction. When reached, remaining API results are still saved without snapshot enrichment so the Actor does not time out.",
                        "default": 480
                    },
                    "anthropicApiKey": {
                        "title": "Anthropic API key for Vision fallback",
                        "type": "string",
                        "description": "Optional. Used only when semantic selectors and text scan cannot find CTA text. Leave empty to avoid Vision LLM cost."
                    },
                    "relaxSearchOnNoResults": {
                        "title": "Relax search when exact keyword has no results",
                        "type": "boolean",
                        "description": "When enabled, a multi-word keyword such as 'pillow sleep' is retried with the first word if the exact active search returns 0 ads. Useful for n8n sheets so strict phrases do not produce empty datasets.",
                        "default": true
                    },
                    "failOnNoResults": {
                        "title": "Fail when no ads are found",
                        "type": "boolean",
                        "description": "When enabled, the Actor fails instead of silently succeeding with an empty dataset. Recommended for n8n so token/API/filter problems are visible.",
                        "default": true
                    },
                    "forceMode": {
                        "title": "Scraping mode",
                        "enum": [
                            "auto",
                            "api",
                            "browser"
                        ],
                        "type": "string",
                        "description": "api = lowest cost and no proxy. auto = API first, then DATACENTER browser fallback. browser = browser only for debugging.",
                        "default": "api"
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
