# Meta Ads Library Scraper + AI Creative Analysis (`jy-labs/meta-ad-creative-intelligence`) Actor

Scrape Facebook Ads Library / Meta Ad Library ads by keyword or Page ID, then optionally enrich image/video creatives with AI hooks, offers, CTAs, OCR/on-screen text, visual tone, video timeline-lite frames, and marketer notes. Raw scraping remains available with no Creative Metadata event charges.

- **URL**: https://apify.com/jy-labs/meta-ad-creative-intelligence.md
- **Developed by:** [Juyeop Park](https://apify.com/jy-labs) (community)
- **Categories:** Social media, Marketing, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $200.00 / 1,000 creative video timeline lite metadata

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## 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

## Facebook Ads Library Scraper + AI Creative Analysis

Scrape public ads from Facebook Ads Library / Meta Ad Library, then optionally turn selected Facebook, Instagram, Messenger, Threads, and Audience Network creatives into structured AI-powered marketing intelligence.

Use raw mode to collect ads by keyword or exact Facebook Page ID. Turn on Creative Metadata when you want each image or short video analyzed for hooks, offers, CTAs, visual tone, OCR/on-screen text, timeline frames, and marketer review notes.

### How this differs from a regular Facebook ads scraper

Most Meta or Facebook Ad Library scrapers stop at raw ad rows: advertiser, copy, dates, CTA links, platforms, and media URLs. This Actor keeps that raw export path, then adds an optional paid Creative Metadata layer for marketers who need to understand **why** a creative works:

- `rawOnly`: zero Creative Metadata event charges; best for broad ad collection.
- `crawlAndAnalyze`: collect fresh ads and analyze a capped number of image/video creatives in one run.
- `analyzeDataset`: enrich an existing raw dataset after you have already selected the creatives worth analyzing.

Use it when you need competitive ad research, hook/offer/CTA teardown, OCR/on-screen text extraction, video timeline-lite evidence, and BI/Sheets-friendly creative labels — not just another raw export.

### Why use this Actor?

- Find competitor ads by brand, keyword, product, exact Facebook Page ID, or Facebook Ads Library search term.
- Export raw Meta Ad Library data: copy, CTA links, media URLs, start dates, active status, and platforms.
- Add AI creative metadata only when needed, without breaking the raw scraper output.
- Analyze ad creatives for hook type, offer, CTA clarity, visual tone, brand presence, product visibility, and narrative structure.
- Get video timeline-lite frame analysis for short videos.
- Export clean JSON/CSV for Sheets, BI dashboards, creative swipe files, and downstream AI workflows.

### Two modes

| Mode              | Best for                                                                                   | Cost behavior                          |
| ----------------- | ------------------------------------------------------------------------------------------ | -------------------------------------- |
| Raw scraping      | Collecting Meta Ad Library ads, copy, media URLs, platforms, and CTA links                 | No Creative Metadata event charge      |
| Creative Metadata | Competitor creative research, ad teardown, swipe files, marketer review, AI-ready datasets | Charged only for completed AI analyses |

Raw scraping works without a Gemini API key. Creative Metadata requires the Actor's `GEMINI_API_KEY` secret to be configured.

### What this Actor returns

Base ad fields:

- `libraryID`
- `keyword`
- `pageId`
- `brand`
- `brandImg`
- `body`
- `startDate`
- `isActive`
- `platforms`
- `images`
- `videos`
- `ctaLink`
- `scrapeDate`

Optional premium field:

- `creativeMetadata`

`creativeMetadata` includes:

- English-only creative labels grouped into `T1`, `T2`, and `T3`.
- Static image context or video timeline-lite keyframe context.
- Hook, offer, CTA, pain point, persuasion angle, and visual tone.
- OCR/on-screen text translated or normalized to English when visible.
- Marketer review notes: strengths, weaknesses, and recommended tests.
- Capped label suggestions for human review.
- Low-confidence fields, provider usage, and charge metadata.

### Pricing in plain English

Creative Metadata uses pay-per-event pricing and is charged only after an AI analysis completes successfully as `completed` or `completed_partial`.

| Event                          | Charged when                                                | Current launch price |
| ------------------------------ | ----------------------------------------------------------- | -------------------: |
| `creative_image_basic`         | One image creative metadata row completes successfully      |              `$0.05` |
| `creative_video_timeline_lite` | One video timeline-lite metadata row completes successfully |              `$0.20` |

Important pricing rules:

- Raw scraping with `includeCreativeMetadata=false` triggers no Creative Metadata event charges.
- `completed` and `completed_partial` metadata rows are charged only after schema-normalized AI output is available.
- `skipped`, `failed_pre_provider`, `failed_provider`, `charge_failed`, no-media, expired media URL, media fetch failure, provider failure, and budget-capped rows are not charged for Creative Metadata.
- `mediaType=meme` uses Meta Ad Library's meme filter. If Meta returns a row without extractable image or video media, Creative Metadata is skipped with `failureCode: "no_media"` and charge 0.
- Apify platform usage, residential proxy usage, and applicable taxes/VAT may apply according to the user's Apify plan, billing location, and platform billing rules.
- The Actor includes safety caps so users can control provider cost and analysis volume.

Recommended first run:

1. Use the Store example as a low-cost AI teaser: `mediaType: "image"`, `maxResults: 3`, and `maxAnalyzedMediaPerRun: 1`. It can show Creative Metadata while capping analysis breadth.
2. For zero Creative Metadata event charges, run raw mode with `maxResults: 5-10` to validate the keyword or exact Page ID first.
3. After selecting the strongest creatives, enable Creative Metadata or use `analyzeDataset` to enrich only those rows.
4. Keep `maxAnalyzedMediaPerRun` and `analysisBudgetUsd` low while testing a new niche or country.

### Example input

Low-cost AI teaser used by the Store example:

```json
{
    "keywords": ["Nike"],
    "country": "US",
    "mediaType": "image",
    "pipelineMode": "crawlAndAnalyze",
    "maxResults": 3,
    "includeCreativeMetadata": true,
    "metadataTier": "image_basic_or_video_timeline_lite",
    "maxAnalyzedMediaPerRun": 1,
    "maxFramesPerVideo": 6,
    "maxVideoDurationSec": 60,
    "analysisBudgetUsd": 0.25,
    "proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
````

Raw scraping only, with no Creative Metadata event charges:

```json
{
    "keywords": ["Nike"],
    "country": "US",
    "pipelineMode": "rawOnly",
    "maxResults": 10,
    "includeCreativeMetadata": false,
    "proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

Creative Metadata enabled for a selected small batch:

```json
{
    "keywords": ["Nike"],
    "country": "US",
    "mediaType": "all",
    "pipelineMode": "crawlAndAnalyze",
    "maxResults": 10,
    "includeCreativeMetadata": true,
    "metadataTier": "image_basic_or_video_timeline_lite",
    "maxAnalyzedMediaPerRun": 5,
    "maxFramesPerVideo": 6,
    "maxVideoDurationSec": 60,
    "analysisBudgetUsd": 1.0,
    "saveRawFrames": false,
    "saveRawMedia": false,
    "proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

### Creative Metadata controls

Default settings are conservative:

```json
{
    "includeCreativeMetadata": false,
    "metadataTier": "image_basic_or_video_timeline_lite",
    "maxAnalyzedMediaPerRun": 20,
    "maxFramesPerVideo": 6,
    "maxVideoDurationSec": 60,
    "maxVideoBytes": 100000000,
    "analysisBudgetUsd": 3.0,
    "saveRawFrames": false,
    "saveRawMedia": false,
    "debugSavePageScreenshot": false
}
```

Important rules:

- Before a provider call, the Actor checks that the matching PPE event is configured and still chargeable within the run budget. If not, the row is skipped before Gemini is called.
- `COST_SUMMARY` records pricing-safety evidence including event price, realized net revenue after Apify margin from successful charges, provider cost, gross margin after provider, and provider-cost/net-revenue ratios.
- If Gemini returns HTTP 200 but malformed or empty JSON after consuming provider tokens, the row is marked as `failed_provider` with `failureCode: "gemini_malformed_json"` and Creative Metadata charge 0. Provider-cost evidence remains visible in `COST_SUMMARY` so failures are auditable without billing the user for unusable metadata.
- Completed metadata charges are retried on transient Apify charge API errors before the row is marked as uncharged, reducing provider-cost leakage from temporary billing API failures.
- Static image rows that complete metadata analysis always include exactly one image timeline item with `time: "image"` and `timestampSec: 0`.
- `labelSuggestions` is capped to 5 items and is review-only. The Actor never auto-adds suggestions to a vocabulary.
- Videos longer than `maxVideoDurationSec` use timeline-lite first-N-second sampling and emit `completed_partial` when metadata completes; failed media/tooling/provider/budget paths remain charge 0.
- No raw video, frame files, or page screenshots are saved by default.
- `PAGE_SCREENSHOT` is written to the key-value store only when `debugSavePageScreenshot` is explicitly set to `true`.
- Output is normalized to English/ASCII-safe text to improve CSV, Sheets, and BI compatibility.
- Media URLs, raw frame paths, page screenshot data, and API keys are not logged.

### Example `creativeMetadata` shape

The shortened example below is based on a verified static-image QA sample from run `sOVBbfkoEFnqYt06i` (`buildNumber: 0.2.37`, `buildId: LapGcoMPAFKgzsVJT`). It analyzed one raw row from source dataset `ql6ElCzNPL7fauVkp` / source run `UWNN5E6PhYUf2b24d` and wrote one enriched row to dataset `Mg7MkiqLwtNBxe5kV` with KVS `fFvdoNedCkS9K1LXF`. The row was returned for keyword `Nike` with brand field `Nicholas Ralph`; treat it as a third-party ad match, not an advertiser-owned Nike example. URL/media fields are omitted from this README excerpt, but every field shown below is copied from that run's dataset item or `COST_SUMMARY`.

```json
{
    "libraryID": "1388117083374637",
    "keyword": "Nike",
    "brand": "Nicholas Ralph",
    "body": "A fresh take on the Nike Mind 001. New colorways, same standout look. Shop the latest pairs now.",
    "startDate": "2026-06-16",
    "isActive": true,
    "platforms": ["Facebook", "Instagram", "Audience Network", "Messenger", "Threads"],
    "source": {
        "type": "dataset",
        "sourceDatasetId": "ql6ElCzNPL7fauVkp",
        "sourceRunId": "UWNN5E6PhYUf2b24d",
        "sourceItemIndex": 0,
        "dedupeKeySource": "creativeFingerprint"
    },
    "creativeMetadata": {
        "status": "completed",
        "mediaType": "image",
        "languagePolicy": "english_only",
        "tier": "image_basic",
        "provider": "gemini",
        "model": "gemini-2.5-flash-lite",
        "analysisCoverage": "static_image",
        "frameCount": 1,
        "samplingPolicy": "static_image",
        "failureCode": "",
        "T1": {
            "hookType": "sale",
            "messageCore": "Factory direct sale up to 70% off limited time only.",
            "format": "image",
            "visualTone": "promotional",
            "talentType": "none",
            "endingCta": "Shop now, limited stock, act fast!",
            "durationSec": 0,
            "targetTone": "urgent",
            "subtitleKeywords": []
        },
        "T2": {
            "transcriptEnglish": "unknown",
            "onScreenTextEnglish": "FACTORY DIRECT SALE UP TO 70% OFF LIMITED TIME ONLY! NO MIDDLEMAN BETTER PRICE PREMIUM RECOVERY SLIDES LIGHTWEIGHT FEELS LIKE WALKING ON CLOUDS BREATHABLE KEEP YOUR FEET COOL & DRY ALL-DAY COMFORT SUPPORTS EVERY STEP YOU TAKE FREE SHIPPING ON ALL ORDERS 30-DAY RISK FREE RETURN POLICY SHOP NOW LIMITED STOCK - ACT FAST!",
            "narrativeStructure": "informational",
            "claims": ["Up to 70% off", "Limited time only", "No middleman, better price", "Lightweight", "Breathable"],
            "offer": "Up to 70% off sale on premium recovery slides.",
            "painPoint": "unknown"
        },
        "T3": {
            "visualComposition": "product-focused",
            "productVisibility": "high",
            "brandPresence": "low",
            "ctaClarity": "high",
            "persuasionAngle": "discount-driven",
            "complianceSignals": ["Free shipping", "Risk-free return policy"]
        },
        "timeline": [
            {
                "time": "image",
                "timestampSec": 0,
                "frameIndex": 0,
                "description": "The image displays a sale advertisement for premium recovery slides. Key text includes \"FACTORY DIRECT SALE\", \"UP TO 70% OFF\", and \"LIMITED TIME ONLY!\". The slides are shown prominently with features like \"LIGHTWEIGHT\", \"BREATHABLE\", and \"ALL-DAY COMFORT\" listed. \"FREE SHIPPING ON ALL ORDERS\" and \"30-DAY RISK FREE RETURN POLICY\" are also visible. The call to action is \"SHOP NOW LIMITED STOCK - ACT FAST!\".",
                "visibleTextEnglish": [
                    "FACTORY DIRECT",
                    "SALE",
                    "UP TO",
                    "70%",
                    "OFF",
                    "LIMITED TIME ONLY!",
                    "NO MIDDLEMAN",
                    "BETTER PRICE",
                    "PREMIUM RECOVERY SLIDES",
                    "LIGHTWEIGHT",
                    "FEELS LIKE WALKING ON CLOUDS",
                    "BREATHABLE",
                    "KEEP YOUR FEET COOL & DRY",
                    "ALL-DAY COMFORT",
                    "SUPPORTS EVERY STEP YOU TAKE",
                    "FREE SHIPPING",
                    "ON ALL ORDERS",
                    "30-DAY RISK FREE",
                    "RETURN POLICY",
                    "SHOP NOW"
                ],
                "objects": ["slides", "text", "icon"],
                "sceneType": "static_image"
            }
        ],
        "creativeReview": {
            "summary": "This is a visually striking image ad for a sale on recovery slides. It effectively uses bold text and clear calls to action to convey a sense of urgency and value. The product features are well-articulated, and trust signals like free shipping and a risk-free return policy are present.",
            "strengths": [
                "Clear and prominent sale messaging",
                "Strong call to action",
                "Highlights key product benefits",
                "Includes trust signals (free shipping, return policy)"
            ],
            "weaknesses": [
                "No visible brand logo for the slides themselves",
                "Limited context on the specific brand of slides"
            ],
            "marketerNotes": [
                "Consider adding the brand logo if available.",
                "Test different discount percentages or sale durations."
            ],
            "recommendedTests": [
                "A/B test different headlines emphasizing discount vs. product benefits.",
                "Test variations of the CTA button text.",
                "Experiment with different background imagery or product angles."
            ]
        },
        "lowConfidenceFields": [],
        "technical": {
            "mimeType": "image/jpeg",
            "frameCount": 1,
            "sampleTimestampsSec": [0],
            "rawMediaSaved": false,
            "rawFramesSaved": false,
            "providerLatencyMs": 4852,
            "providerEstimatedCostUsd": 0.0028383
        },
        "charge": {
            "eligible": true,
            "applied": true,
            "eventName": "creative_image_basic",
            "chargedCount": 1,
            "eventChargeLimitReached": false
        }
    }
}
```

Grounded static-image evidence from the same output:

| Field                | Value from verified image sample                                                                                                                     |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Run / build          | `sOVBbfkoEFnqYt06i` / `0.2.37` / `LapGcoMPAFKgzsVJT`                                                                                                 |
| Dataset / item count | `Mg7MkiqLwtNBxe5kV` / `1`                                                                                                                            |
| KVS evidence         | `fFvdoNedCkS9K1LXF` with `COST_SUMMARY`                                                                                                              |
| Creative status      | `completed`                                                                                                                                          |
| Media type / tier    | `image` / `image_basic`                                                                                                                              |
| Timeline evidence    | `time: "image"`, `timestampSec: 0`, `frameIndex: 0`                                                                                                  |
| Visible text sample  | `FACTORY DIRECT`, `SALE`, `UP TO`, `70%`, `OFF`, `LIMITED TIME ONLY!`, `NO MIDDLEMAN`, `BETTER PRICE`, `PREMIUM RECOVERY SLIDES`, `LIGHTWEIGHT`, ... |
| Charge object        | `eventName: creative_image_basic`, `chargedCount: 1`, `applied: true`                                                                                |
| Run charged events   | `creative_image_basic: 1`, `creative_video_timeline_lite: 0`                                                                                         |
| Raw artifact flags   | `rawMediaSaved: false`, `rawFramesSaved: false`                                                                                                      |

`COST_SUMMARY` excerpt from the same KVS:

```json
{
    "key": "COST_SUMMARY",
    "providerCallCount": 1,
    "estimatedProviderCostUsd": 0.0028383,
    "eventPriceUsd": {
        "creative_image_basic": 0.05
    },
    "netRevenueAfterApifyUsd": {
        "creative_image_basic": 0.04
    },
    "providerCostUsd": 0.0028383,
    "grossMarginAfterProviderUsd": 0.0371617,
    "providerCostToNetRevenueRatio": 0.0709575,
    "chargeAttemptCount": 1,
    "chargeSuccessCount": 1,
    "chargeFailureCount": 0,
    "statusCounters": {
        "not_requested": 0,
        "skipped": 0,
        "failed_pre_provider": 0,
        "failed_provider": 0,
        "completed": 1,
        "completed_partial": 0,
        "charge_failed": 0
    },
    "chargedEventCounts": {
        "creative_image_basic": 1
    }
}
```

### Gemini API key setup

Creative Metadata requires a Gemini API key. Raw scraping does not.

The Actor reads the key only from the `GEMINI_API_KEY` environment variable or Apify Secret configured in Apify Console. The source bundle references a product secret alias only; it does not contain a key value. The key is never printed to logs, dataset rows, key-value store records, or README examples.

#### How to set or change the key in Apify Console

1. Open Apify Console.
2. Go to this Actor.
3. Open **Settings** or **Environment variables / Secrets**.
4. Add or update the secret used by `GEMINI_API_KEY` (current alias: `metaAdCreativeIntelligenceGeminiApiKey`).
5. Save the change.
6. Start a new run so the new environment value is used.

If `includeCreativeMetadata` is `false`, the Actor makes zero provider calls even when no key is configured.

If `includeCreativeMetadata` is `true` and the key is missing or invalid, affected rows fail at the metadata level with a clear `creativeMetadata.status` and `failureCode`. The key value is never exposed.

### Operational notes

- Use Apify Residential proxy for reliable Meta Ad Library pagination.
- Start with small `maxResults` and `maxAnalyzedMediaPerRun` values while validating a new keyword or brand.
- Provider cost is controlled by `analysisBudgetUsd`, media count caps, video duration caps, and frame caps.
- This Actor is not affiliated with, endorsed by, or sponsored by Meta, Facebook, or Instagram.
- This Actor does not provide legal or policy compliance decisions. Use the output as creative intelligence for human review.

# Actor input Schema

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

Keywords to search for ads in rawOnly or crawlAndAnalyze mode. Not required for analyzeDataset mode.

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

Optional. If you want to collect ads from a specific advertiser with precision, provide the exact view\_all\_page\_id value of that advertiser's Facebook Page. Each entry is matched by index to keywords — pageIds\[0] applies to keywords\[0], pageIds\[1] to keywords\[1], and so on. When a Page ID is set, the search is restricted to that advertiser's page only, significantly improving the accuracy of collected data. Leave an entry blank to use keyword-only search at that position. Find the Page ID by searching the advertiser in Meta Ad Library and copying the numeric ID from the URL (view\_all\_page\_id=XXXXXXXXX). Example: \["", "123456789"] skips Page ID for keywords\[0] and restricts keywords\[1] to page 123456789.

## `pipelineMode` (type: `string`):

Separates raw crawling from AI metadata analysis. rawOnly writes raw ads only with provider/charge 0. analyzeDataset reads a source dataset and writes enriched output. crawlAndAnalyze persists raw ads to a named dataset before AI analysis and writes one enriched row per ad to the default dataset.

## `sourceDatasetId` (type: `string`):

Required for analyzeDataset mode. Raw ad dataset ID to enrich. Enriched output includes source.sourceDatasetId, source.sourceRunId, source.sourceItemIndex, source.sourceDedupeKey, and source.dedupeKeySource.

## `sourceRunId` (type: `string`):

Optional for analyzeDataset mode. Stored as source.sourceRunId; output uses null when unknown/not provided.

## `rawDatasetName` (type: `string`):

Optional base name for crawlAndAnalyze raw persistence. A run-scoped suffix is added so raw rows do not mix across runs.

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

Country code to search ads in

## `adType` (type: `string`):

Type of ads to search

## `activeStatus` (type: `string`):

Filter by ad active status

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

Filter by media type. The meme filter is passed through to Meta Ad Library; if a returned meme-filtered row has no extractable image or video media, Creative Metadata is skipped with charge 0.

## `startDateMin` (type: `string`):

Filter ads that started running on or after this date. Leave empty for no minimum date filter.

## `startDateMax` (type: `string`):

Filter ads that started running on or before this date. Leave empty for no maximum date filter.

## `sortBy` (type: `string`):

Sort order for search results

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

Maximum number of ads to collect per keyword

## `proxy` (type: `object`):

Proxy settings for accessing Meta Ad Library. RESIDENTIAL proxy is required — Facebook rate-limits GraphQL pagination from datacenter IPs, causing scroll to fail silently with zero new ads.

## `requestHandlerTimeoutSecs` (type: `integer`):

Maximum time to wait for the Ad Library page to load per keyword. Increase if you experience timeout errors on slow connections.

## `includeCreativeMetadata` (type: `boolean`):

Legacy compatibility switch. If pipelineMode is omitted, true maps to crawlAndAnalyze and false maps to rawOnly. Explicit pipelineMode is preferred.

## `metadataTier` (type: `string`):

Current tier: static image basic analysis or video timeline-lite analysis with bounded keyframes.

## `creativeAnalysisDepth` (type: `string`):

Opt-in AI output depth. basic preserves the existing public Actor output style. strategyLabels adds BI-friendly Strategy Labels v1. strategyLabelsAndVideoStrategy also asks video ads for intro/middle/end strategy, offer timing, CTA timing, and stage labels. Public pricing is unchanged; cost guards still apply.

## `maxAnalyzedMediaPerRun` (type: `integer`):

Maximum number of ads whose media will be sent to the AI provider in one run. Additional rows are skipped with charge 0.

## `maxFramesPerVideo` (type: `integer`):

Maximum scene/keyframes extracted from each analyzed video. Hard capped at 12. Default is 6.

## `maxVideoDurationSec` (type: `integer`):

Timeline-lite analyzes a bounded first-N-second window with scene/keyframe sampling for long videos instead of processing the full video. Default 60 seconds.

## `videoSamplingStrategy` (type: `string`):

Opt-in sampling control for long videos. firstWindow preserves existing behavior by sampling the first N seconds. introMiddleEnd samples bounded frames from the beginning, middle, and end so strategy labels can reason about hook, body, offer, and CTA placement without raising the 12-frame cap.

## `maxVideoBytes` (type: `integer`):

Maximum media bytes to download for analysis. Larger media is skipped with charge 0.

## `analysisBudgetUsd` (type: `number`):

Estimated provider cost cap. When the projected next call would exceed this cap, provider calls stop and remaining metadata rows are skipped with charge 0.

## `saveRawFrames` (type: `boolean`):

Reserved debug flag. Current build always cleans temporary extracted frames and reports rawFramesSaved=false; no raw frame artifacts are persisted.

## `saveRawMedia` (type: `boolean`):

Reserved debug flag. Current build always cleans temporary downloaded media and reports rawMediaSaved=false; no raw media artifacts are persisted.

## `geminiModel` (type: `string`):

Gemini model used for creative metadata. Default is cost-efficient Flash-Lite.

## `debugSavePageScreenshot` (type: `boolean`):

Debug-only. When enabled, saves PAGE\_SCREENSHOT to the key-value store after the final keyword. Default is OFF so normal runs do not store page-level image artifacts.

## Actor input object example

```json
{
  "keywords": [
    "Nike"
  ],
  "pipelineMode": "rawOnly",
  "country": "US",
  "adType": "all",
  "activeStatus": "all",
  "mediaType": "all",
  "sortBy": "relevancy_monthly_grouped",
  "maxResults": 5,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "requestHandlerTimeoutSecs": 300,
  "includeCreativeMetadata": false,
  "metadataTier": "image_basic_or_video_timeline_lite",
  "creativeAnalysisDepth": "basic",
  "maxAnalyzedMediaPerRun": 20,
  "maxFramesPerVideo": 6,
  "maxVideoDurationSec": 60,
  "videoSamplingStrategy": "firstWindow",
  "maxVideoBytes": 100000000,
  "analysisBudgetUsd": 3,
  "saveRawFrames": false,
  "saveRawMedia": false,
  "geminiModel": "gemini-2.5-flash-lite",
  "debugSavePageScreenshot": false
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `creative_intelligence` (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 = {
    "keywords": [
        "Nike"
    ],
    "country": "US",
    "maxResults": 5,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("jy-labs/meta-ad-creative-intelligence").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 = {
    "keywords": ["Nike"],
    "country": "US",
    "maxResults": 5,
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("jy-labs/meta-ad-creative-intelligence").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 '{
  "keywords": [
    "Nike"
  ],
  "country": "US",
  "maxResults": 5,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call jy-labs/meta-ad-creative-intelligence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=jy-labs/meta-ad-creative-intelligence",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Meta Ads Library Scraper + AI Creative Analysis",
        "description": "Scrape Facebook Ads Library / Meta Ad Library ads by keyword or Page ID, then optionally enrich image/video creatives with AI hooks, offers, CTAs, OCR/on-screen text, visual tone, video timeline-lite frames, and marketer notes. Raw scraping remains available with no Creative Metadata event charges.",
        "version": "0.2",
        "x-build-id": "Nr2CGsuNZJWTcr7tl"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/jy-labs~meta-ad-creative-intelligence/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-jy-labs-meta-ad-creative-intelligence",
                "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/jy-labs~meta-ad-creative-intelligence/runs": {
            "post": {
                "operationId": "runs-sync-jy-labs-meta-ad-creative-intelligence",
                "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/jy-labs~meta-ad-creative-intelligence/run-sync": {
            "post": {
                "operationId": "run-sync-jy-labs-meta-ad-creative-intelligence",
                "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": {
                    "keywords": {
                        "title": "Search Keywords",
                        "maxItems": 5,
                        "type": "array",
                        "description": "Keywords to search for ads in rawOnly or crawlAndAnalyze mode. Not required for analyzeDataset mode.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "pageIds": {
                        "title": "Page IDs (optional)",
                        "maxItems": 5,
                        "type": "array",
                        "description": "Optional. If you want to collect ads from a specific advertiser with precision, provide the exact view_all_page_id value of that advertiser's Facebook Page. Each entry is matched by index to keywords — pageIds[0] applies to keywords[0], pageIds[1] to keywords[1], and so on. When a Page ID is set, the search is restricted to that advertiser's page only, significantly improving the accuracy of collected data. Leave an entry blank to use keyword-only search at that position. Find the Page ID by searching the advertiser in Meta Ad Library and copying the numeric ID from the URL (view_all_page_id=XXXXXXXXX). Example: [\"\", \"123456789\"] skips Page ID for keywords[0] and restricts keywords[1] to page 123456789.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "pipelineMode": {
                        "title": "Pipeline Mode",
                        "enum": [
                            "rawOnly",
                            "analyzeDataset",
                            "crawlAndAnalyze"
                        ],
                        "type": "string",
                        "description": "Separates raw crawling from AI metadata analysis. rawOnly writes raw ads only with provider/charge 0. analyzeDataset reads a source dataset and writes enriched output. crawlAndAnalyze persists raw ads to a named dataset before AI analysis and writes one enriched row per ad to the default dataset.",
                        "default": "rawOnly"
                    },
                    "sourceDatasetId": {
                        "title": "Source Dataset ID",
                        "type": "string",
                        "description": "Required for analyzeDataset mode. Raw ad dataset ID to enrich. Enriched output includes source.sourceDatasetId, source.sourceRunId, source.sourceItemIndex, source.sourceDedupeKey, and source.dedupeKeySource."
                    },
                    "sourceRunId": {
                        "title": "Source Run ID",
                        "type": "string",
                        "description": "Optional for analyzeDataset mode. Stored as source.sourceRunId; output uses null when unknown/not provided."
                    },
                    "rawDatasetName": {
                        "title": "Raw Dataset Name",
                        "type": "string",
                        "description": "Optional base name for crawlAndAnalyze raw persistence. A run-scoped suffix is added so raw rows do not mix across runs."
                    },
                    "country": {
                        "title": "Country",
                        "enum": [
                            "KR",
                            "US",
                            "JP",
                            "GB",
                            "DE",
                            "FR",
                            "CA",
                            "AU",
                            "BR",
                            "IN",
                            "MX",
                            "ES",
                            "IT",
                            "NL",
                            "SG",
                            "TW",
                            "HK",
                            "TH",
                            "VN",
                            "ID",
                            "PH",
                            "MY",
                            "ALL"
                        ],
                        "type": "string",
                        "description": "Country code to search ads in",
                        "default": "KR"
                    },
                    "adType": {
                        "title": "Ad Type",
                        "enum": [
                            "all",
                            "political_and_issue_ads"
                        ],
                        "type": "string",
                        "description": "Type of ads to search",
                        "default": "all"
                    },
                    "activeStatus": {
                        "title": "Active Status",
                        "enum": [
                            "all",
                            "active",
                            "inactive"
                        ],
                        "type": "string",
                        "description": "Filter by ad active status",
                        "default": "all"
                    },
                    "mediaType": {
                        "title": "Media Type",
                        "enum": [
                            "all",
                            "image",
                            "meme",
                            "video",
                            "none"
                        ],
                        "type": "string",
                        "description": "Filter by media type. The meme filter is passed through to Meta Ad Library; if a returned meme-filtered row has no extractable image or video media, Creative Metadata is skipped with charge 0.",
                        "default": "all"
                    },
                    "startDateMin": {
                        "title": "Start Date (From)",
                        "type": "string",
                        "description": "Filter ads that started running on or after this date. Leave empty for no minimum date filter."
                    },
                    "startDateMax": {
                        "title": "Start Date (To)",
                        "type": "string",
                        "description": "Filter ads that started running on or before this date. Leave empty for no maximum date filter."
                    },
                    "sortBy": {
                        "title": "Sort By",
                        "enum": [
                            "relevancy_monthly_grouped",
                            "total_impressions"
                        ],
                        "type": "string",
                        "description": "Sort order for search results",
                        "default": "relevancy_monthly_grouped"
                    },
                    "maxResults": {
                        "title": "Max Results",
                        "minimum": 1,
                        "maximum": 200,
                        "type": "integer",
                        "description": "Maximum number of ads to collect per keyword",
                        "default": 100
                    },
                    "proxy": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Proxy settings for accessing Meta Ad Library. RESIDENTIAL proxy is required — Facebook rate-limits GraphQL pagination from datacenter IPs, causing scroll to fail silently with zero new ads.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    },
                    "requestHandlerTimeoutSecs": {
                        "title": "Page Load Timeout (seconds)",
                        "minimum": 60,
                        "maximum": 600,
                        "type": "integer",
                        "description": "Maximum time to wait for the Ad Library page to load per keyword. Increase if you experience timeout errors on slow connections.",
                        "default": 300
                    },
                    "includeCreativeMetadata": {
                        "title": "Include Creative Metadata",
                        "type": "boolean",
                        "description": "Legacy compatibility switch. If pipelineMode is omitted, true maps to crawlAndAnalyze and false maps to rawOnly. Explicit pipelineMode is preferred.",
                        "default": false
                    },
                    "metadataTier": {
                        "title": "Metadata Tier",
                        "enum": [
                            "image_basic_or_video_timeline_lite"
                        ],
                        "type": "string",
                        "description": "Current tier: static image basic analysis or video timeline-lite analysis with bounded keyframes.",
                        "default": "image_basic_or_video_timeline_lite"
                    },
                    "creativeAnalysisDepth": {
                        "title": "Creative Analysis Depth",
                        "enum": [
                            "basic",
                            "strategyLabels",
                            "strategyLabelsAndVideoStrategy"
                        ],
                        "type": "string",
                        "description": "Opt-in AI output depth. basic preserves the existing public Actor output style. strategyLabels adds BI-friendly Strategy Labels v1. strategyLabelsAndVideoStrategy also asks video ads for intro/middle/end strategy, offer timing, CTA timing, and stage labels. Public pricing is unchanged; cost guards still apply.",
                        "default": "basic"
                    },
                    "maxAnalyzedMediaPerRun": {
                        "title": "Max Analyzed Media Per Run",
                        "minimum": 0,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Maximum number of ads whose media will be sent to the AI provider in one run. Additional rows are skipped with charge 0.",
                        "default": 20
                    },
                    "maxFramesPerVideo": {
                        "title": "Max Frames Per Video",
                        "minimum": 1,
                        "maximum": 12,
                        "type": "integer",
                        "description": "Maximum scene/keyframes extracted from each analyzed video. Hard capped at 12. Default is 6.",
                        "default": 6
                    },
                    "maxVideoDurationSec": {
                        "title": "Video Timeline-Lite Analysis Window Seconds",
                        "minimum": 1,
                        "maximum": 300,
                        "type": "integer",
                        "description": "Timeline-lite analyzes a bounded first-N-second window with scene/keyframe sampling for long videos instead of processing the full video. Default 60 seconds.",
                        "default": 60
                    },
                    "videoSamplingStrategy": {
                        "title": "Video Sampling Strategy",
                        "enum": [
                            "firstWindow",
                            "introMiddleEnd"
                        ],
                        "type": "string",
                        "description": "Opt-in sampling control for long videos. firstWindow preserves existing behavior by sampling the first N seconds. introMiddleEnd samples bounded frames from the beginning, middle, and end so strategy labels can reason about hook, body, offer, and CTA placement without raising the 12-frame cap.",
                        "default": "firstWindow"
                    },
                    "maxVideoBytes": {
                        "title": "Max Video Bytes",
                        "minimum": 1000000,
                        "maximum": 200000000,
                        "type": "integer",
                        "description": "Maximum media bytes to download for analysis. Larger media is skipped with charge 0.",
                        "default": 100000000
                    },
                    "analysisBudgetUsd": {
                        "title": "Provider Budget Cap USD",
                        "minimum": 0,
                        "maximum": 100,
                        "type": "number",
                        "description": "Estimated provider cost cap. When the projected next call would exceed this cap, provider calls stop and remaining metadata rows are skipped with charge 0.",
                        "default": 3
                    },
                    "saveRawFrames": {
                        "title": "Save Raw Frames",
                        "type": "boolean",
                        "description": "Reserved debug flag. Current build always cleans temporary extracted frames and reports rawFramesSaved=false; no raw frame artifacts are persisted.",
                        "default": false
                    },
                    "saveRawMedia": {
                        "title": "Save Raw Media",
                        "type": "boolean",
                        "description": "Reserved debug flag. Current build always cleans temporary downloaded media and reports rawMediaSaved=false; no raw media artifacts are persisted.",
                        "default": false
                    },
                    "geminiModel": {
                        "title": "Gemini Model",
                        "type": "string",
                        "description": "Gemini model used for creative metadata. Default is cost-efficient Flash-Lite.",
                        "default": "gemini-2.5-flash-lite"
                    },
                    "debugSavePageScreenshot": {
                        "title": "Save Debug Page Screenshot",
                        "type": "boolean",
                        "description": "Debug-only. When enabled, saves PAGE_SCREENSHOT to the key-value store after the final keyword. Default is OFF so normal runs do not store page-level image artifacts.",
                        "default": false
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
