# AI Ad Creative Analyzer – Facebook Ad Hooks & Angles (`sarel-data/ai-ad-creative-analyzer`) Actor

Analyze competitor Facebook & Instagram ads with AI: scrapes the Meta Ad Library and extracts hook, angle, offer, CTA, emotional trigger, format, audience and a winner signal (days running). Optional video transcription. Bring your own LLM key or use the free built-in analyzer.

- **URL**: https://apify.com/sarel-data/ai-ad-creative-analyzer.md
- **Developed by:** [Sarel Data](https://apify.com/sarel-data) (community)
- **Categories:** AI, Social media
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 1,000 ad analyzeds

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

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

## AI Ad Creative Analyzer – Facebook Ad Analyzer for Ad Hooks, Angles & Competitor Ads AI

**Find out *why* your competitors' Facebook and Instagram ads work.** This **Facebook ad analyzer** scrapes the public Meta Ad Library, transcribes video ads, and uses AI to break every ad down into **hook, angle, offer, CTA, emotional trigger, format, target audience and a "winner" signal** based on how many days the ad has been running. You get a clean dataset plus a summary of the **top ad hooks and angles** across all ads — ready for your next creative brief.

Use it for **competitor ads AI research**, swipe files, creative strategy, UGC briefs and ad-angle testing.

### What you get per ad

| Field | Example |
|---|---|
| `hook` | "The pieces everyone's talking about." |
| `hookType` | question, bold_claim, statistic_number, pain_point, offer_first, story, curiosity_gap… |
| `angle` | social_proof, problem_solution, scarcity_urgency, discount_price, transformation, ugc_testimonial, product_feature… |
| `offer` / `offerType` | "20% off your first order" / discount |
| `cta` | Shop now |
| `emotionalTrigger` | fear_of_missing_out, greed_savings, belonging, pride_status, curiosity, trust_safety… |
| `format` | video, single_image, carousel_image, catalog_dpa, dynamic_creative |
| `targetAudienceGuess` | "women 18–30 into gym fashion" |
| `daysRunning` / `longevitySignal` / `longevityScore` | 202 / likely_winner / 87 |
| `transcript` | Spoken voice-over of video ads |
| Raw ad data | ad text, headline, image & video URLs, start/end dates, platforms (Facebook, Instagram, Messenger, Audience Network), page name, Ad Library link |

**Longevity = likely winner.** Advertisers keep paying for ads that convert. An ad running 60+ days is flagged `likely_winner`, 30+ days `proven`, 7+ days `testing`, under 7 days `new`.

### Summary record: top hooks & angles

At the end of each run you get a summary (key-value store record `SUMMARY`, and the last dataset item with `recordType: "summary"`):

- Top 10 hooks ranked by days running
- Share of each angle, hook type, emotional trigger, offer type, format and CTA — with the average days running for each, so you see which angles last longest
- Top 5 longest-running ("winner") ads with links

### Bring your own AI key – or use it free

- **AI analysis:** paste your own **OpenAI, Anthropic (Claude), Google Gemini, OpenRouter, Groq** or any OpenAI-compatible key. You pay your LLM provider directly. A small model like gpt-4o-mini typically costs well under $0.001 per ad.
- **No key?** A built-in rule-based analyzer fills the same fields for free (less nuanced than an LLM).
- **Video transcription (off by default; set `transcriptionProvider`, use 4 GB+ memory for `local`):** runs **open-source Whisper locally (faster-whisper)** inside the Actor at no extra API cost, or uses your OpenAI or Groq Whisper key if you want it faster or more accurate.

Keys are marked secret, stored encrypted by Apify and never written to logs or output.

### How to use

1. Enter an **advertiser Page ID** (or an Ad Library URL with `view_all_page_id=`), and/or **keywords / brand names**.
2. Choose a **country** and, if you want, a **date range** (ads that started between two dates).
3. Set **Max ads to analyze**.
4. Optional: choose an AI provider and paste your API key.
5. Run. Export as JSON, CSV, Excel, or use the API.

#### Example input

```json
{
  "searchTerms": ["Gymshark"],
  "searchType": "keyword_exact_phrase",
  "country": "US",
  "maxAds": 50,
  "llmProvider": "openai",
  "llmApiKey": "sk-...",
  "transcriptionProvider": "none"
}
```

#### Example output (one ad)

```json
{
  "recordType": "ad",
  "pageName": "Shopify1Percent",
  "format": "video",
  "transcript": "We have a conspicuous consumption behavior in our ecosystem...",
  "hook": "We have a conspicuous consumption behavior in our ecosystem...",
  "hookType": "statement",
  "angle": "ugc_testimonial",
  "cta": "Visit Instagram profile",
  "emotionalTrigger": "joy_excitement",
  "daysRunning": 202,
  "longevitySignal": "likely_winner",
  "method": "heuristic",
  "snapshotUrl": "https://www.facebook.com/ads/library/?id=1980082592608739"
}
```

### Pricing

Pay per analyzed ad: you pay only for ads that are actually analyzed. LLM usage is billed by your own provider, using your own key.

### FAQ

**Is it legal to scrape the Meta Ad Library?** The Ad Library is a public transparency tool. This Actor only collects publicly visible ad data. Follow your local laws and Meta's terms.

**How do I find a Page ID?** Open the advertiser in the Ad Library and copy the number after `view_all_page_id=` in the URL, or paste that whole URL.

**Why are some transcripts empty?** The video has music only (no speech), or the transcription limit was reached.

**Does it cover Instagram ads?** Yes. Meta Ad Library includes ads on Facebook, Instagram, Messenger and Audience Network.

**Related:** Facebook ad analyzer, Facebook ads spy tool, ad hooks generator research, competitor ads AI, Meta Ad Library scraper, ad creative analysis, winning ads finder, swipe file builder.

### Cost & proxy defaults

The Actor runs with **1 GB memory** by default, which is enough for scraping and the built-in analysis. Transcription is **off by default**; if you turn on local Whisper, raise memory to 4 GB. It connects **directly first** and only routes a request through the fallback proxy (Residential by default) after Facebook blocks it, so most runs use little or no proxy bandwidth. To send all traffic through the proxy, turn off `directFirst`.

# Actor input Schema

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

Numeric Page IDs (or Ad Library URLs containing view_all_page_id=). Returns every ad the Page runs.

## `searchTerms` (type: `array`):

Keywords to search, one per line. Each term is a separate search.

## `startUrls` (type: `array`):

Paste any search URL from facebook.com/ads/library. Filters in the URL are used as-is and override the filters below.

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

Two-letter country code (US, GB, FR, DE...) or ALL.

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

Facebook's own date filter: keeps ads that were delivering on or after this date (YYYY-MM-DD). Combine with "Filter by start date" for ads that *started* in the range.

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

Keeps ads that were delivering on or before this date (YYYY-MM-DD).

## `maxAds` (type: `integer`):

Total ads scraped and analyzed across all inputs.

## `llmProvider` (type: `string`):

Your own LLM key is used for analysis, so you pay the LLM provider directly (typically well under $0.001 per ad with small models). Without a key, a built-in rule-based analyzer fills the same fields.

## `llmApiKey` (type: `string`):

Your API key for the provider above. Stored encrypted, never logged.

## `llmModel` (type: `string`):

Defaults: gpt-4o-mini, claude-3-5-haiku-latest, gemini-2.0-flash, openai/gpt-4o-mini (OpenRouter), llama-3.3-70b-versatile (Groq).

## `llmBaseUrl` (type: `string`):

For the "custom" provider: an OpenAI-compatible base URL such as https://my-host/v1.

## `transcriptionProvider` (type: `string`):

Video ads are downloaded and the voice-over is transcribed so the spoken hook can be analyzed. "Local" runs faster-whisper inside the Actor at no API cost. Off by default. "local" (free Whisper on CPU) is slow and needs 4 GB+ memory – raise run memory if you enable it.

## `transcriptionApiKey` (type: `string`):

Required only for the OpenAI/Groq transcription options.

## `localWhisperModel` (type: `string`):

Bigger = more accurate but slower and needs more memory.

## `maxTranscribeSeconds` (type: `integer`):

Only the first N seconds are transcribed (hooks live in the first seconds).

## `maxVideosToTranscribe` (type: `integer`):

Cap on video downloads/transcriptions per run.

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

Ad category

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

Active status

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

Media type

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

Keyword matching

## `platforms` (type: `array`):

Leave empty for all platforms.

## `strictStartDate` (type: `boolean`):

Also drop ads whose start date is outside the range above (e.g. long-running ads that started earlier).

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

Sort

## `includeAdDetails` (type: `boolean`):

Adds EU reach (total and by age/gender/country), targeting, payer/beneficiary, page spend and Instagram info. Most useful with EU countries. Slower: one extra request per ad.

## `deduplicateAcrossInputs` (type: `boolean`):

Save an ad only once even if several inputs return it.

## `maxConcurrency` (type: `integer`):

Parallel browsers

## `maxRequestRetries` (type: `integer`):

Each retry uses a fresh browser session and proxy IP.

## `analysisConcurrency` (type: `integer`):

Parallel transcription/analysis workers.

## `includeSummaryInDataset` (type: `boolean`):

Adds a final item with recordType="summary" (top hooks, angles, triggers). Always saved to key-value store record SUMMARY too.

## `directFirst` (type: `boolean`):

Connect without a proxy first (cheapest) and use the proxy below only after Facebook blocks a request. Turn off to send all traffic through the proxy.

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

Fallback proxy. By default the actor connects directly and switches to this proxy only when Facebook blocks it. Residential is recommended as the fallback.

## Actor input object example

```json
{
  "pageIds": [
    "15087023444"
  ],
  "country": "US",
  "maxAds": 10,
  "llmProvider": "none",
  "transcriptionProvider": "none",
  "localWhisperModel": "tiny",
  "maxTranscribeSeconds": 120,
  "maxVideosToTranscribe": 50,
  "adType": "all",
  "activeStatus": "active",
  "mediaType": "all",
  "searchType": "keyword_unordered",
  "strictStartDate": false,
  "sortBy": "relevancy",
  "includeAdDetails": false,
  "deduplicateAcrossInputs": true,
  "maxConcurrency": 3,
  "maxRequestRetries": 6,
  "analysisConcurrency": 3,
  "includeSummaryInDataset": true,
  "directFirst": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

One item per ad with AI creative analysis, plus a final summary item.

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

Aggregated top hooks, angles, triggers, offers and winners.

## `runStats` (type: `string`):

Summary of inputs processed, ads saved and blocks retried.

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "pageIds": [
        "15087023444"
    ],
    "maxAds": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("sarel-data/ai-ad-creative-analyzer").call(input);

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = {
    "pageIds": ["15087023444"],
    "maxAds": 10,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("sarel-data/ai-ad-creative-analyzer").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "pageIds": [
    "15087023444"
  ],
  "maxAds": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call sarel-data/ai-ad-creative-analyzer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sarel-data/ai-ad-creative-analyzer"
        }
    }
}
```

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

## OpenAPI specification

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