Ad Creative Intelligence — Transcript, Hook, On-Screen Text
Pricing
from $37.50 / 1,000 video_analyzeds
Ad Creative Intelligence — Transcript, Hook, On-Screen Text
Turns ad video URLs into transcripts with timestamps, on-screen text, the first-3-seconds hook and the detected CTA. Pay per analyzed video, no login, no API key.
Pricing
from $37.50 / 1,000 video_analyzeds
Rating
0.0
(0)
Developer
Andrey Kurilov
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Ad Creative Intelligence — Transcript, On-Screen Text, Hook & CTA | $50/1k videos | No Login
Turn a list of ad video URLs into structured creative intelligence: a full transcript with timestamps, the text burned onto the screen, the first-3-seconds hook and the call to action — one JSON object per creative, $0.03 per analyzed video.
What it solves
Getting the ads themselves is a commodity — a dozen Ad Library scrapers do it for $0.15–1.00 per 1 000. The question your team actually asks is one level up: what is said in the creative, what is written on it, and what is the hook that stops the scroll?
This actor is the second step in that pipeline. It takes the media URLs you already have and gives back the analysis layer:
- Hook — what the creative opens with in the first 3 seconds, the window performance
buyers benchmark. Both channels are reported: what is spoken there and what is burned onto
the opening frames, because a modern creative usually carries the hook in both at once.
Cut on word timings, so a single long spoken segment does not spill the whole script into
the hook. A creative that opens on music has no hook in the window — you get an empty
hook.textwithemptyReasonandfirstSpeechStartSec, the hook delay, rather than a line quoted from the middle of the ad. - Transcript — segments with timestamps, plus a flat
transcriptPlainstring to pipe into an LLM. - On-screen text — offers, prices and captions burned into the video, read off key frames.
- CTA — the detected call to action and where it appears.
- Pace and identity — scene-change count and a perceptual hash of the creative.
Typical recipe: Meta Ad Library Scraper ($0.15/1k) → this actor → your hook library.
Built for performance agencies and media buyers, UGC studios building hook libraries, brands monitoring competitors, and ad-intelligence tools that need a speech layer without running the infrastructure.
Input example
{"videos": [{"url": "https://archive.org/download/OlayTotalEffectsAdvert/Olay%20Total%20Effects%20Advert.ia.mp4","meta": { "adId": "OlayTotalEffectsAdvert" }},{"url": "https://archive.org/download/LOrealElviveDavidGinolaAdvert1998/L%27Oreal%20Elvive%20David%20Ginola%20Advert.ia.mp4","meta": { "adId": "LOrealElviveDavidGinolaAdvert1998" }}],"language": "auto","asrModel": "fast","extractOnScreenText": true,"maxFrames": 12,"hookWindowSeconds": 3,"skipIfNoSpeech": false,"maxVideoDurationSeconds": 300,"maxConcurrency": 6}
Only videos is required. Send batches, not single URLs: every run has a fixed start-up cost that is
billable, so 20 videos is the smallest sensible run and 100–500 is the sweet spot.
Input fields
| Field | Type | Default | Description |
|---|---|---|---|
videos | array | — | Items with a direct media url and optional meta passed through to the output. Required. |
language | string | auto | Keep auto. Forcing the wrong language is the most common source of garbage transcripts. |
asrModel | enum | fast | fast (4 GB) or accurate (8 GB, better on noisy or music-heavy ads, doubles the compute cost). |
extractOnScreenText | boolean | true | Run OCR over key frames. Turn off for a cheaper audio-only pass. |
maxFrames | integer | 12 | Cap on key frames per video, picked by scene-change detection. |
hookWindowSeconds | integer | 3 | Length of the opening window reported as the hook. |
skipIfNoSpeech | boolean | false | Report silent videos as no_content without running OCR. |
maxVideoDurationSeconds | integer | 300 | Hard ceiling. Longer videos fail for $0. Can be lowered, never raised. |
maxConcurrency | integer | 6 | Upper bound on videos in flight. The run lowers it to what the memory you gave it can keep busy. |
Output example
Real output for the first video of the input above — this is what the actor returned on the platform, not an illustration.
{"sourceUrl": "https://archive.org/download/OlayTotalEffectsAdvert/Olay%20Total%20Effects%20Advert.ia.mp4","adId": "OlayTotalEffectsAdvert","status": "ok","failureReason": null,"durationSec": 19.621,"language": "en","hasSpeech": true,"hook": {"text": "You can either buy an anti-aging cream that works in lines and wrinkles","windowSec": 3,"spokenWords": 13,"source": "speech","spokenText": "You can either buy an anti-aging cream that works in lines and wrinkles","onScreenText": null,"firstSpeechStartSec": 0.14,"emptyReason": null},"transcript": [{"start": 0.14,"end": 9.2,"text": "You can either buy an anti-aging cream that works in lines and wrinkles or one designed to work on pores, blotches, tone, texture, radiance and lines and wrinkles.","confidence": 0.8313},{ "start": 9.48, "end": 14.4, "text": "Only one cream guarantees to reduce the appearance of all seven signs of aging or your money back.", "confidence": 0.8313 },{ "start": 14.92, "end": 15.44, "text": "Total Effects.", "confidence": 0.8313 }],"transcriptPlain": "You can either buy an anti-aging cream that works in lines and wrinkles or one designed to work on pores, blotches, tone, texture, radiance and lines and wrinkles. Only one cream guarantees to reduce the appearance of all seven signs of aging or your money back. Total Effects. Not a difficult choice. Total Effects from Ole.","onScreenText": [{ "atSec": 1.96, "text": "A", "confidence": 0.7936 }],"cta": null,"sceneChanges": 6,"perceptualHash": "01694949418a0400","meta": { "adId": "OlayTotalEffectsAdvert", "sourceDurationSec": 19.6, "bytes": 1918100 },"processedAt": "2026-09-14T11:17:05.746Z"}
This creative opens on the voiceover, so source is speech. On a creative that opens on a
text card with the presenter a beat behind, source is both and the card is in
onScreenText — 10 of the 40 creatives in the measured batch were that shape. On one that
opens on music, text is null, emptyReason is speech_starts_later, and
firstSpeechStartSec tells you how late: that was 8 of the 40.
Output fields
| Field | Type | Description |
|---|---|---|
sourceUrl | string | The submitted media URL. Normalized, it is also the charging key. |
adId | string | null | Copied from meta.adId. |
status | ok | no_content | failed | ok — speech or on-screen text found; no_content — processed but empty; failed — unusable media. |
failureReason | string | null | unreachable, unsupported_media, too_long, timeout, internal_error. |
durationSec | number | null | Video duration. |
language | string | null | ISO 639-1 code detected from the audio. |
hasSpeech | boolean | Whether any speech was recognized. |
hook | object | null | The opening window: text, spokenText, onScreenText, windowSec, spokenWords, source (speech, on_screen, both or null), firstSpeechStartSec, emptyReason. Null only when the video failed. On a no_content video the object is present and emptyReason says why it is empty. |
transcript | array | { start, end, text, confidence } segments in chronological order. |
transcriptPlain | string | null | The whole transcript as one flat string, for LLM input. |
onScreenText | array | { atSec, text, confidence }, deduplicated across frames. |
cta | object | null | { text, atSec, source } where source is on_screen or speech. |
sceneChanges | integer | null | Detected scene changes — a proxy for editing pace. |
perceptualHash | string | null | Fingerprint of the creative, for spotting the same ad under another advertiser. |
meta | object | null | Your input meta, unchanged. |
processedAt | string | UTC ISO-8601 timestamp. |
The full typed schema lives in .actor/dataset_schema.json, so MCP clients and LLM agents can pick the actor up without guessing.
Pricing
Pay per event. You are never charged for a failure.
Billed per started 30 seconds of video, because that is how the work scales. A 15-second creative costs less than it did under the old flat rate; a two-minute one finally pays for the two minutes of transcription it takes.
| Event | Price | When |
|---|---|---|
actor-start | $0.010 | Once per run. |
video_analyzed | $0.050 | Video processed, speech or on-screen text found. Covers the first 30 s. |
video_extra_block | $0.050 | Each started 30 s beyond the first. |
video_no_content | $0.010 | Video processed, nothing found. Covers the first 30 s. |
video_failed | $0.000 | Media unreachable, broken, longer than the duration limit — or a stage of ours failed and produced nothing. No event is reported at all, so it cannot appear on your invoice. |
That is $50 per 1,000 creatives up to 30 seconds, which is how ad creatives are actually counted. Pricing per media-minute would be the wrong unit here and misleading: because a started block is billed whole, a 15-second creative works out at $100 per 1,000 real minutes and an 8-second one at $188. You buy analyses of creatives, not minutes of audio.
Calculator — a typical batch of 500 creatives, 470 with content, most of them short:
actor-start 1 × $0.010 = $0.01video_analyzed 470 × $0.050 = $23.50video_extra_block 90 over 30 s × $0.050 = $4.50video_no_content 20 × $0.010 = $0.20video_failed 10 × $0.000 = $0.00───────500 creatives $28.21 (≈ $0.056 per creative)
For comparison, the closest listing in the store returns a transcript and on-screen text — no hook, no CTA, no scene count, no perceptual hash — and charges $75 per 1,000.
Set ACTOR_MAX_TOTAL_CHARGE_USD on the run to cap the spend: when the cap is hit the run
finishes cleanly and keeps everything already stored in the dataset — it does not crash,
and it does not charge twice for a retried video.
What you are guaranteed
Nothing leaves the run. Everything is computed on the Apify machine you pay for — no third-party transcription service, no external AI provider, no key of yours or of ours. There is nothing to sign up for, nothing to rate-limit you, and your creatives are not handed to anyone.
A partial result is still a result. If one half of the analysis cannot be produced, you get the other half rather than an error — and you are charged the normal rate, because a transcript without on-screen text is still worth having.
Our breakage is never your bill. An empty result looks the same whether the creative
carried nothing or something on our side failed to read it. The two are told apart
explicitly: nothing found and everything worked → no_content from $0.010; nothing found
because something broke → failed / internal_error at $0.000.
More memory is faster at the same price. Doubling the memory roughly halves the time and
costs the same in total. Pick memory for how quickly you want the batch back, not to save
money — and leave maxConcurrency alone unless the media host is slow.
FAQ
Do I need a Facebook/TikTok login, cookies or an API key? No. The actor takes media URLs you already have and downloads them over plain HTTP.
Does it scrape the Ad Library? No, by design. Ad Library scrapers are a commodity at $0.15/1k — use one of those and feed its output here. That also keeps this actor complementary to the tools you already run.
What if the same video appears twice in a batch? The charging key is the normalized URL, so you are billed once per creative even across retries of the same run.
Which languages? Transcription covers ~99 languages and the language is auto-detected from the audio — do not set it by hand unless you are certain. CTA detection covers English, Spanish, Portuguese and German.
How long may a video be?
300 seconds by default, and that is a hard cap. Anything longer is reported as
failed / too_long and charged $0, so one stray long-form video cannot eat your budget.
Can I run it on a schedule? Yes. A failed result reports no billable event at all and an empty one starts at $0.010, so polling is cheap.
Limitations
- Direct media URLs only; resolving an ad ID to a media URL is not implemented in v1.
- The
ctafield is the call to action inside the creative — burned into a frame or spoken in the voiceover. It is not the Ad Library button ("Shop now", "Learn more"): that is rendered by Meta outside the video and cannot be recovered from the file. If you need it, it comes from the Ad Library scraper that fed you these URLs, in itsctaText. Measured against Meta's own labels on 5 live creatives, our field agreed 0 times — by construction, not by failure. - No face recognition, no biometric processing, no personal-data extraction — not now, not on request.
- Transcripts are produced for analysis; the actor never republishes the source media.
- Quality on heavily music-covered voiceovers is lower — check
confidencerather than assuming. - Videos above 256 MB are reported as
unsupported_media. - A caption that flashes on and off very briefly can be missed. Raise
maxFramesfor text-dense creatives. - The same caption seen more than once is reported once, near-identical misreadings included. A caption whose wording genuinely changes later stays a separate entry.
Roadmap
- v1 — this scope: transcript, on-screen text, hook, CTA, scene changes, perceptual hash.
- v2 — hook typology (question / shock-stat / problem / demo / testimonial), sentiment, offer and price extraction, creative deduplication by perceptual hash.
- v3 — Standby mode for agents, MCP tool, cross-platform comparison of one creative.
Disclaimer
You are responsible for complying with the terms of service of the platforms your media comes from and with applicable data-protection law. This actor analyzes advertising creatives; do not use it on private, personal or paywalled content.