# Instagram Reel OCR & Hook Extractor (`automation-lab/instagram-reel-ocr-hooks`) Actor

Extract timestamped on-screen text, opening hooks, transcript context, creator metadata, and provenance from public Instagram Reels or creator handles.

- **URL**: https://apify.com/automation-lab/instagram-reel-ocr-hooks.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Social media, Marketing, AI
- **Stats:** 3 total users, 2 monthly users, 86.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $42.00 / 1,000 reel analyzeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Instagram Reel OCR & Hook Extractor

Turn public Instagram Reels into timestamped on-screen text, opening hooks, speech transcript context, creator metadata, and source provenance.

This Actor is designed for creative strategists, paid-social teams, agencies, and researchers who need the words viewers see—not only the words they hear. Supply Reel URLs, creator handles, or both. Each successful result is a typed record ready for a spreadsheet, scheduled comparison, API pipeline, or LLM workflow.

### What this Instagram Reel analyzer does

For every successfully processed public Reel, the Actor:

1. opens the public Instagram Reel in an anonymous browser session;
2. resolves and downloads the public video without an Instagram login;
3. samples frames at your chosen interval;
4. performs local Tesseract OCR on each frame;
5. removes consecutive duplicate OCR observations;
6. selects the first useful on-screen text in the hook window;
7. optionally creates a timestamped speech transcript with faster-whisper;
8. falls back to speech or caption context when early OCR is unavailable;
9. returns creator, duration, shortcode, canonical URL, and processing provenance.

The default dataset contains one record per successfully analyzed Reel. Failed, private, deleted, photo-only, login-only, oversized, or over-duration inputs are not charged as Reel results.

### Who is it for?

- **Creative strategists** building libraries of opening-hook patterns.
- **Paid-social teams** comparing the copy shown during the first seconds.
- **Agencies** reviewing public competitor or client creative with authorization.
- **Creator teams** exporting their own on-screen copy for reuse and QA.
- **Researchers** studying public short-form video language over time.
- **Data teams** feeding timestamped OCR into a warehouse or classification model.
- **Automation builders** scheduling repeatable Reel batches through Apify.

### Why use OCR instead of transcript-only extraction

Speech transcription misses silent title cards, burned-in subtitles, stickers, calls to action, disclaimers, handles, and text shown over music.

This Actor keeps two signals separate:

- `ocrFrames` and `onScreenText` represent visible text sampled from the video;
- `transcript` and `transcriptSegments` represent recognized speech when enabled.

The `hookSource` field says whether the selected opening hook came from on-screen text, speech, or page caption context. That provenance helps downstream workflows avoid treating every hook as spoken dialogue.

### Extracted Instagram Reel data

| Field | Meaning |
| --- | --- |
| `sourceUrl` | Supplied Reel URL or creator profile that produced the result |
| `canonicalUrl` | Normalized public Reel URL |
| `shortcode` | Instagram Reel shortcode |
| `creatorUsername` | Visible public creator username, when available |
| `creatorProfileUrl` | Public creator profile URL |
| `caption` | Public page description used as context |
| `durationSeconds` | Rendered video duration |
| `hookText` | Opening hook selected from OCR, speech, or caption |
| `hookSource` | `on-screen-text`, `transcript`, or `caption` |
| `onScreenText` | Timestamp-ordered OCR text joined for export |
| `ocrFrames` | Deduplicated timestamp, text, and OCR confidence objects |
| `transcript` | Speech transcript when enabled and speech is detected |
| `transcriptLanguage` | Detected transcript language |
| `transcriptSegments` | Timestamped speech segments |
| `frameIntervalSeconds` | Sampling interval used by the run |
| `ocrLanguage` | Tesseract language model used |
| `extractionMethod` | Processing-route provenance |
| `processedAt` | ISO 8601 completion time |

### Getting started

1. Open the Actor input page.
2. Add one or more public Instagram Reel URLs under **Instagram Reel URLs**.
3. Optionally add public handles under **Creator handles**.
4. Set **Maximum Reels** to control total output.
5. Choose an OCR language.
6. Keep speech transcript enabled when spoken context matters.
7. Run the Actor.
8. Open the **Reel OCR and hooks** dataset view.
9. Export JSON, CSV, Excel, XML, or connect the dataset API.

A reliable first test is the prefilled public BBC News Reel with `maxItems: 1`.

### Input parameters

| Input | Type | Default | Notes |
| --- | --- | --- | --- |
| `startUrls` | array | prefilled Reel | Public `/reel/`, `/p/`, or `/tv/` video URLs |
| `creators` | string array | `[]` | Handles such as `bbcnews` or public profile URLs |
| `maxItems` | integer | `3` | Total successful records, from 1 to 20 |
| `maxReelsPerCreator` | integer | `3` | Recent Reel links per creator, from 1 to 10 |
| `frameIntervalSeconds` | number | `1.5` | Frame sampling interval from 0.5 to 5 seconds |
| `hookWindowSeconds` | number | `4` | Opening window from 1 to 10 seconds |
| `ocrLanguage` | enum | `eng` | English, Spanish, German, or French OCR |
| `includeTranscript` | boolean | `true` | Runs local speech recognition when enabled |
| `maxVideoDurationSeconds` | integer | `180` | Rejects videos above the configured 5–600 second limit |
| `proxyConfiguration` | object | direct | Optional Apify Proxy configuration |

At least one Reel URL or creator handle is required.

### Reel URL example

```json
{
  "startUrls": [
    { "url": "https://www.instagram.com/reel/DV29mBcMQwp/" }
  ],
  "maxItems": 1,
  "frameIntervalSeconds": 3,
  "hookWindowSeconds": 6,
  "ocrLanguage": "eng",
  "includeTranscript": true,
  "maxVideoDurationSeconds": 180,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

### Creator-handle example

Instagram currently serves creator profile discovery less consistently than a direct Reel. A US residential proxy is useful for this route and is never enabled automatically.

```json
{
  "creators": ["bbcnews"],
  "maxItems": 1,
  "maxReelsPerCreator": 1,
  "frameIntervalSeconds": 5,
  "includeTranscript": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "US"
  }
}
```

Direct Reel URLs remain the lower-cost, more deterministic input route.

### Output example

The following shortened example reflects the current output shape. OCR text varies with video design and selected frame interval.

```json
{
  "sourceUrl": "https://www.instagram.com/reel/DV29mBcMQwp/",
  "canonicalUrl": "https://www.instagram.com/reel/DV29mBcMQwp/",
  "shortcode": "DV29mBcMQwp",
  "creatorUsername": "bbcnews",
  "durationSeconds": 68.2,
  "hookText": "Satellite images show destroyed Iranian aircraft",
  "hookSource": "on-screen-text",
  "onScreenText": "Satellite images show destroyed Iranian aircraft\nThis follows video released by the US",
  "ocrFrames": [
    {
      "timestampSeconds": 0,
      "text": "Satellite images show destroyed Iranian aircraft",
      "confidence": 78.4
    }
  ],
  "transcriptLanguage": "en",
  "frameIntervalSeconds": 3,
  "ocrLanguage": "eng",
  "processedAt": "2026-01-15T12:00:00.000Z"
}
```

`caption`, `hookText`, creator fields, and transcript fields can be `null` when Instagram or the video does not expose that signal.

### How opening hooks are selected

The Actor examines OCR observations whose timestamps fall within `hookWindowSeconds`.

- The first useful early OCR observation becomes `hookText`.
- If early OCR is empty and transcription is enabled, early speech becomes the hook.
- If both are empty, public caption context is used when available.
- `hookSource` records the chosen route.

This is deterministic extraction, not a subjective performance score. It does not claim that a hook is effective or predict engagement.

### OCR quality tips

- Use `frameIntervalSeconds: 0.5` or `1` for very brief overlays.
- Use `2` to `5` seconds for lower-cost monitoring of longer, slower-changing videos.
- Match `ocrLanguage` to the dominant on-screen language.
- Decorative fonts, motion blur, low contrast, tiny text, and heavy compression reduce confidence.
- OCR confidence is diagnostic, not a guarantee that every word is correct.
- Compare `ocrFrames` rather than only the joined `onScreenText` when timing matters.

### Transcript behavior

Speech transcription uses a local, compact faster-whisper model.

- No external speech-to-text API key is required.
- Transcript processing adds runtime.
- Music-only or silent videos can return `null` transcript fields.
- OCR output remains available even when no speech is detected.
- Timestamped transcript segments provide context; they are not separately charged.

Disable `includeTranscript` when visible copy is the only required signal.

### How much does it cost to extract Instagram Reel hooks?

The Actor uses pay per event pricing:

- one `start` event per run: **$0.005**;
- one `reel` event for each successfully analyzed result;
- failed or rejected Reels do not emit the `reel` event.

Current per-Reel tiers are:

| Plan | Price per successful Reel |
| --- | ---: |
| Free | $0.0805 |
| Bronze | $0.0700 |
| Silver | $0.0546 |
| Gold | $0.0420 |
| Platinum | $0.0280 |
| Diamond | $0.0196 |

At Bronze pricing, one successful Reel costs about **$0.075** including the one-time start event. Five successful Reels in one run cost about **$0.355**. Ten cost about **$0.705**.

Proxy transfer is an Apify platform cost and can vary by proxy type. In creator mode, only the small profile-discovery JSON request uses the configured proxy; Reel rendering and media transfer stay direct to avoid duplicate residential video traffic.

### Scheduling creative monitoring

Create a saved Task with a stable list of public Reel URLs, then schedule it daily or weekly.

A recurring workflow can:

1. run the same input set;
2. write a new default dataset snapshot;
3. export `shortcode`, `hookText`, and `ocrFrames`;
4. compare the snapshot with the previous run;
5. notify a team when visible copy changes.

The Actor itself does not store a cross-run history or send alerts. Use Apify schedules, webhooks, integrations, or your data warehouse for those steps.

### Spreadsheet and data-pipeline workflows

Useful downstream patterns include:

- export `hookText` and `creatorUsername` to Google Sheets;
- flatten `ocrFrames` into one timestamped row per observation;
- group hook phrases by creator or campaign;
- compare visible copy with `transcript` to find text-only messages;
- feed OCR text to a permitted topic or CTA classifier;
- retain `canonicalUrl` and `processedAt` for provenance.

Apify datasets can be downloaded as JSON, CSV, Excel, XML, RSS, or JSONL.

### Run through the Apify API with cURL

Replace `YOUR_APIFY_TOKEN` with your token.

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~instagram-reel-ocr-hooks/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url": "https://www.instagram.com/reel/DV29mBcMQwp/"}],
    "maxItems": 1,
    "includeTranscript": true
  }'
```

To wait and retrieve dataset items:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~instagram-reel-ocr-hooks/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":[{"url":"https://www.instagram.com/reel/DV29mBcMQwp/"}],"maxItems":1}'
```

### JavaScript API example

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/instagram-reel-ocr-hooks').call({
  startUrls: [{ url: 'https://www.instagram.com/reel/DV29mBcMQwp/' }],
  maxItems: 1,
  frameIntervalSeconds: 2,
  includeTranscript: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].hookText, items[0].ocrFrames);
```

### Python API example

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/instagram-reel-ocr-hooks').call(run_input={
    'startUrls': [{'url': 'https://www.instagram.com/reel/DV29mBcMQwp/'}],
    'maxItems': 1,
    'frameIntervalSeconds': 2,
    'includeTranscript': True,
})

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['hookText'])
```

### Use with MCP and AI assistants

Add this Actor to Claude Code through Apify MCP:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/instagram-reel-ocr-hooks"
```

#### Claude Desktop

Add this server object to Claude Desktop's MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/instagram-reel-ocr-hooks"
    }
  }
}
```

#### Cursor

Add the same `apify` server URL in **Cursor Settings → MCP**.

#### VS Code

Add the same HTTP MCP server URL to your VS Code MCP configuration, then select the Actor tool from the available Apify tools.

Example prompts:

- “Extract the opening on-screen hook and timestamped text from this public Reel.”
- “Compare the visible opening copy in these three authorized Instagram Reels.”
- “Analyze one recent public Reel from this creator and return OCR frames without speech transcription.”

Always review OCR before making high-impact decisions.

### Proxy guidance

Direct public Reel URLs are the default and cheapest route.

Creator profile discovery is more frequently rate-limited or redirected to login. For that route:

- configure an Apify residential proxy explicitly; only the small creator-profile JSON request uses it, while Reel rendering and media stay direct;
- use the geography relevant to the public profile surface;
- keep `maxReelsPerCreator` bounded;
- reuse one coherent run session;
- avoid treating a login/challenge page as an empty successful result.

The Actor never silently turns on residential traffic.

### Limits and failure behavior

- Only public Instagram Reel/video content is supported.
- Private profiles and login-only content are not supported.
- Stories and expiring private media are not supported.
- Photo-only posts do not produce a Reel record.
- Maximum input is 20 successfully processed Reels per run.
- Maximum configured duration is 600 seconds.
- Video downloads above the safety limit fail.
- A failed input is not charged as a Reel.
- Successful results are preserved if another input later fails.
- The run fails visibly when any requested input fails, so partial gaps are not hidden.
- Instagram can change its public delivery surfaces without notice.

### Responsible and legal use

Use this Actor only for public content you are permitted to process.

You are responsible for complying with applicable laws, Instagram terms, copyright, privacy obligations, contractual restrictions, and organizational policies. Do not use the Actor to bypass access controls, process private content, identify sensitive personal traits, harass creators, or republish copyrighted video without permission.

Store only the data you need, protect exported datasets, respect deletion requests where applicable, and keep human review in decisions that affect people.

### Troubleshooting

#### Why did creator discovery return a login or challenge error?

Instagram often treats profile discovery differently from a direct Reel. Configure a US residential proxy, reduce the number of creators, and retry in a new run. If you already know the Reel URLs, provide them directly.

#### Why is the OCR text noisy?

Try a smaller frame interval and verify the OCR language. Low contrast, motion, stylized fonts, and complex backgrounds can still reduce accuracy. Use timestamps and confidence values during review.

#### Why is the transcript null?

The Reel may contain no speech, speech may be too quiet, or `includeTranscript` may be disabled. OCR output can still be useful for silent or music-only Reels.

#### Why did a long Reel fail?

Increase `maxVideoDurationSeconds` within the supported 600-second ceiling, or process a shorter authorized source. Longer videos use more compute and OCR frames.

### FAQ

#### Does it require an Instagram account?

No. It processes anonymously reachable public content and does not accept Instagram credentials.

#### Can it analyze multiple Reels?

Yes. Supply several URLs or creator handles and set `maxItems` up to 20.

#### Does it predict whether a hook will perform well?

No. It extracts the hook signal and provenance. Performance scoring requires your campaign context and outcomes.

#### Does it download videos into the output dataset?

No. Temporary media is deleted after local processing. The default dataset contains text, timestamps, metadata, and provenance.

#### Are OCR and transcript separate charges?

No. They are included in the successful `reel` event. There is no separate OCR-frame or transcript-segment event.

#### Can I use Spanish, German, or French text?

Yes. Select the matching `ocrLanguage`. Speech language is detected automatically when transcript processing is enabled.

### Related automation-lab Actors

- [Instagram Reel & Video Transcript Scraper](https://apify.com/automation-lab/instagram-reel-video-transcripts) — transcript-first extraction for public Instagram videos.
- [Instagram Post & Reel Details Scraper](https://apify.com/automation-lab/instagram-post-reel-details-scraper) — public Reel and post metadata without OCR processing.
- [Video to Text Transcriber](https://apify.com/automation-lab/video-to-text-transcriber) — speech transcription for direct video files or accessible media URLs.

Choose this Actor when timestamped **visible** text and opening-hook provenance are the primary output.

# Actor input Schema

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

Public instagram.com/reel URLs to analyze. Photo posts, private content, Stories, and login-only content are rejected.

## `creators` (type: `array`):

Optional public Instagram handles or profile URLs. The Actor discovers recent Reel links from each public profile.

## `maxItems` (type: `integer`):

Maximum number of successfully analyzed Reel records across direct URLs and creator discovery.

## `maxReelsPerCreator` (type: `integer`):

Maximum recent Reel links collected from each supplied creator profile.

## `frameIntervalSeconds` (type: `number`):

How often to sample a frame for on-screen text. Smaller intervals improve short-overlay coverage but take longer.

## `hookWindowSeconds` (type: `number`):

The opening interval searched for the first on-screen or spoken hook.

## `ocrLanguage` (type: `string`):

Language model used to read on-screen text.

## `includeTranscript` (type: `boolean`):

Run local speech recognition and return timestamped transcript segments for context and hook fallback.

## `maxVideoDurationSeconds` (type: `integer`):

Reject longer videos before processing. Supported range is 5–600 seconds.

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

Optional Apify Proxy settings. Direct access is the default. Residential proxy traffic is never enabled automatically.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.instagram.com/reel/DV29mBcMQwp/"
    }
  ],
  "creators": [],
  "maxItems": 3,
  "maxReelsPerCreator": 3,
  "frameIntervalSeconds": 1.5,
  "hookWindowSeconds": 4,
  "ocrLanguage": "eng",
  "includeTranscript": true,
  "maxVideoDurationSeconds": 180,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Default dataset items in the overview view.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.instagram.com/reel/DV29mBcMQwp/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/instagram-reel-ocr-hooks").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 = { "startUrls": [{ "url": "https://www.instagram.com/reel/DV29mBcMQwp/" }] }

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/instagram-reel-ocr-hooks").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 '{
  "startUrls": [
    {
      "url": "https://www.instagram.com/reel/DV29mBcMQwp/"
    }
  ]
}' |
apify call automation-lab/instagram-reel-ocr-hooks --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/instagram-reel-ocr-hooks"
        }
    }
}

```

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/Mi86HZbSGWqPl0E2t/builds/ZCZRuzrsTP7ngcoyA/openapi.json
