# YouTube, TikTok & Reels Transcript — Video to Text + Hooks (`ntriqpro/video-transcript-hooks`) Actor

Turn YouTube, Shorts, TikTok and Instagram Reels URLs into text: timecoded transcript sentences, full transcript, the opening hook typed and scored, on-screen text, keywords, hashtags and chapters. Captions first, Whisper when there are none. Batch input, pay per result.

- **URL**: https://apify.com/ntriqpro/video-transcript-hooks.md
- **Developed by:** [daehwan kim](https://apify.com/ntriqpro) (community)
- **Categories:** Social media, AI, Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $15.60 / 1,000 full transcripts

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

## YouTube, TikTok & Reels Transcript — Video to Text + Hooks

Paste YouTube videos, YouTube Shorts, TikTok videos and Instagram Reels — up to 200 per run — and get
every video back as text: **timecoded transcript sentences, the full transcript, the opening hook
(typed and scored), on-screen text read from the frames, keywords, hashtags and chapters**, plus the
video's metadata (title, length, views, likes, comments, publish date, author).

Captions are used when the video has them (fast, exact); otherwise the audio is transcribed with
Whisper. One run can mix all three platforms.

> This Actor is an **independent, unofficial tool**. It is **not affiliated with, endorsed by, or
> sponsored by** YouTube, Google, TikTok, ByteDance, Instagram or Meta. It reads public videos as a
> logged-out visitor: no login, no cookies, no CAPTCHA solving. It extracts **text only** — no video or
> audio file is stored in your dataset or redistributed. **You are responsible** for having the right to
> process the videos you submit, for complying with each platform's terms of service and with copyright
> and privacy law, and for how you use the output. Every result row carries this notice in its
> `responsibility` field.

### Who this is for

- **Short-form creators and social media managers** — study the first 3 seconds of winning Reels and
  TikToks: what was said, which hook device was used, what text was on screen.
- **Marketers and agencies** — turn competitor videos into scripts, keywords and hashtags in one pass.
- **Researchers and AI builders** — clean, timecoded transcripts ready for search, RAG or summarising.
- **YouTubers** — chapter lines you can paste straight into a description.

### What one run returns

Each result is its own row (`rowType`), so you can filter, export or join them:

| rowType | One row per | Main fields |
|---|---|---|
| `video` | video | `videoTitle`, `durationSec`, `viewCount`, `likeCount`, `commentCount`, `publishedAt`, `author`, `videoDescription`, `thumbnailUrl` |
| `transcript-segment` | spoken sentence | `timecode`, `startSec`, `endSec`, `segmentText`, `wordCount` |
| `transcript` | video | `transcript` (full text), `wordCount`, `speechRateWpm`, `language`, `engine`, `truncated` |
| `hook` | video | `hookText` (first N seconds), `hookTypes` (question, number, contrast, promise), `hookScore` 0-100, `firstWordSec`, `onscreenTextInHook` |
| `onscreen-text` | distinct on-screen text block | `onscreenText`, `firstSeenSec`, `lastSeenSec`, `frames`, `ocrConfidence` |
| `keywords` | video | `keywords`, `keywordDetails` (count and timestamps), `hashtags` |
| `chapter` | chapter | `chapterTitle`, `startSec`, `endSec`, `youtubeChapter` (e.g. `00:00 What's up guys…`) |
| `notice` | message | `noticeCode`, `message` — never charged |

`engine` tells you where the words came from: `youtube-captions`, `youtube-auto-captions` or
`faster-whisper-base` / `faster-whisper-tiny`.

**How the hook is scored.** The hook is every sentence that starts in the first `hookSeconds` (default 3).
It is tagged with the devices it uses — a **question**, a **number**, a **contrast** ("but", "stop",
"most people…") or a **promise** ("here's how", "you'll", "in 5 days") — and scored 0-100: 20 points per
device, plus 10 when the first word lands within one second and 10 when the hook is 20 words or fewer.
The rules are English; other languages still get the hook text and timing.

### Pricing (pay per event)

| Event | Charged per | USD (FREE plan) | Bronze | Silver | Gold+ |
|---|---|---|---|---|---|
| `run-started` | run | 0.005 | 0.004 | 0.00325 | 0.0026 |
| `video-resolved` | video metadata row | 0.01 | 0.008 | 0.0065 | 0.0052 |
| `transcript-segment` | transcript sentence row | 0.005 | 0.004 | 0.00325 | 0.0026 |
| `transcript-full` | full-transcript row (one per video) | 0.03 | 0.024 | 0.0195 | 0.0156 |
| `hook-extracted` | hook row (one per video) | 0.03 | 0.024 | 0.0195 | 0.0156 |
| `onscreen-text` | on-screen text block row | 0.01 | 0.008 | 0.0065 | 0.0052 |
| `keywords-hashtags` | keywords row (one per video) | 0.02 | 0.016 | 0.013 | 0.0104 |
| `chapter-detected` | chapter row | 0.01 | 0.008 | 0.0065 | 0.0052 |

**What is charged and what is not.**

- A row written to the dataset is charged once under its event. The same video submitted twice (for
  example a Shorts link and a watch link of the same video) is processed and charged once.
- `run-started` is charged once when at least one supported URL is accepted and work begins.
- A video the platform does not serve to a logged-out visitor (private, removed, region-locked,
  login-walled) produces a `video-unavailable` notice and **no charge** for that video.
- Notice rows (`noticeCode`: invalid URL, video unavailable, no speech, on-screen text skipped,
  spending limit) are messages, never charged.
- Switch layers off to pay only for what you need; the video metadata row is always delivered.
- When your maximum charge per run is reached the run stops paid work and ends with a notice row.

**Example:** a 60-second Short with every layer on — 15 sentences, 3 on-screen text blocks, 3 chapters:
start $0.005 + video $0.01 + sentences $0.075 + full transcript $0.03 + hook $0.03 + on-screen text $0.03 +
keywords $0.02 + chapters $0.03 = **about $0.23**. Full transcript only: $0.005 + $0.01 + $0.03 =
**$0.045 per video**.

### Input

```json
{
  "videoUrls": [
    "https://www.youtube.com/shorts/C4exbdl5H-s",
    "https://www.tiktok.com/@tiktok/video/7681695065927912735",
    "https://www.instagram.com/reel/Da_ZgEaPvCN/"
  ],
  "layers": ["transcriptSegments", "transcriptFull", "hook", "onscreenText", "keywords", "chapters"],
  "language": "auto",
  "hookSeconds": 3,
  "whisperModel": "base"
}
```

| Field | Default | Meaning |
|---|---|---|
| `videoUrls` | — | YouTube (watch, Shorts, youtu.be), TikTok (video pages, vm./vt. short links), Instagram (reel, p, tv). Up to 200. |
| `layers` | all | Which rows to produce. |
| `language` | `auto` | Two-letter code to pick a caption track or force Whisper's language. |
| `hookSeconds` | 3 | Hook window, 1-15 seconds. |
| `whisperModel` | `base` | `base` (more accurate) or `tiny` (faster), used only when a video has no captions. |
| `ocrMaxVideoSeconds` | 180 | Longer videos skip the on-screen text layer. |
| `timeoutPerVideo` | 240 | Transcription time limit per video; partial transcripts are marked `truncated`. |
| `proxyConfiguration` | Residential | Used only as a fallback when a platform refuses the direct request. |

### Output example

A real `hook` row from the default input:

```json
{
  "rowType": "hook",
  "platform": "tiktok",
  "videoUrl": "https://www.tiktok.com/@tiktok/video/7681695065927912735",
  "hookText": "Hey, it's Alex Warren. I'm here with TikTok to go through the search files to see what you guys have been looking up about me.",
  "hookTypes": [],
  "hookScore": 10,
  "firstWordSec": 0,
  "hookWordCount": 25,
  "onscreenTextInHook": ["I'm here with TikTok", "to see what you guys"],
  "engine": "faster-whisper-base",
  "language": "en"
}
```

The default input (one Short, one TikTok, one Reel) returns about 115-130 rows in under two minutes.

### Limits worth knowing

- Public videos only. Instagram and TikTok sometimes refuse logged-out visitors, and YouTube blocks many
  cloud IPs; the Actor retries through your proxy once, and videos that still fail get a free
  `video-unavailable` notice.
- On-screen text uses English OCR on one frame every 2 seconds (up to 60 seconds of OCR per video);
  stylised or fast-moving captions can be missed or partly read. When a video is reachable only through
  the proxy, only its audio is fetched and on-screen text is skipped with a free notice.
- Music-only or silent videos return metadata, on-screen text and keywords from hashtags, with a free
  `no-speech` notice.
- Whisper transcription runs on CPU: expect roughly 5-10 seconds per minute of speech with `base`.

### Runs on the Apify platform

Schedule runs, call the Actor from the API, or connect it to Make, Zapier, n8n or an AI agent through
the Apify MCP server. Export results as JSON, CSV or Excel.

### Leave a review

A short review on the **Reviews** tab, good or bad, helps other people find this Actor and tells us what to build next. Found a bug or need a feature? Open an issue on the **Issues** tab and we'll look into it.

# Actor input Schema

## `videoUrls` (type: `array`):

One per line, up to 200: YouTube videos and Shorts, TikTok videos and Instagram Reels (public, no login). Duplicates are processed once. Only submit videos you have the right to process; you are responsible for how you use the output and for each platform's terms.

## `layers` (type: `array`):

Which rows to produce for each video. Leave empty for all. The video metadata row is always delivered.

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

auto detects the spoken language. Or give a two-letter code (en, es, ko, ...) to pick that caption track or force Whisper to that language.

## `hookSeconds` (type: `integer`):

How many opening seconds count as the hook. Sentences that start inside the window are kept whole.

## `whisperModel` (type: `string`):

base is more accurate, tiny is faster. Both are built into the image (no download wait).

## `ocrMaxVideoSeconds` (type: `integer`):

On-screen text is read from one frame every 2 seconds (English OCR). Videos longer than this skip that layer; everything else is still delivered.

## `timeoutPerVideo` (type: `integer`):

Transcription stops after this many seconds per video; the transcript delivered so far is marked truncated.

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

Each video is first fetched directly. The proxy is used only when a platform refuses the direct request (YouTube often blocks cloud IPs).

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/shorts/C4exbdl5H-s",
    "https://www.tiktok.com/@tiktok/video/7681695065927912735",
    "https://www.instagram.com/reel/Da_ZgEaPvCN/"
  ],
  "layers": [
    "transcriptSegments",
    "transcriptFull",
    "hook",
    "onscreenText",
    "keywords",
    "chapters"
  ],
  "language": "auto",
  "hookSeconds": 3,
  "whisperModel": "base",
  "ocrMaxVideoSeconds": 180,
  "timeoutPerVideo": 240,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "videoUrls": [
        "https://www.youtube.com/shorts/C4exbdl5H-s",
        "https://www.tiktok.com/@tiktok/video/7681695065927912735",
        "https://www.instagram.com/reel/Da_ZgEaPvCN/"
    ],
    "layers": [
        "transcriptSegments",
        "transcriptFull",
        "hook",
        "onscreenText",
        "keywords",
        "chapters"
    ],
    "language": "auto",
    "hookSeconds": 3,
    "whisperModel": "base",
    "ocrMaxVideoSeconds": 180,
    "timeoutPerVideo": 240,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ntriqpro/video-transcript-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 = {
    "videoUrls": [
        "https://www.youtube.com/shorts/C4exbdl5H-s",
        "https://www.tiktok.com/@tiktok/video/7681695065927912735",
        "https://www.instagram.com/reel/Da_ZgEaPvCN/",
    ],
    "layers": [
        "transcriptSegments",
        "transcriptFull",
        "hook",
        "onscreenText",
        "keywords",
        "chapters",
    ],
    "language": "auto",
    "hookSeconds": 3,
    "whisperModel": "base",
    "ocrMaxVideoSeconds": 180,
    "timeoutPerVideo": 240,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("ntriqpro/video-transcript-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 '{
  "videoUrls": [
    "https://www.youtube.com/shorts/C4exbdl5H-s",
    "https://www.tiktok.com/@tiktok/video/7681695065927912735",
    "https://www.instagram.com/reel/Da_ZgEaPvCN/"
  ],
  "layers": [
    "transcriptSegments",
    "transcriptFull",
    "hook",
    "onscreenText",
    "keywords",
    "chapters"
  ],
  "language": "auto",
  "hookSeconds": 3,
  "whisperModel": "base",
  "ocrMaxVideoSeconds": 180,
  "timeoutPerVideo": 240,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call ntriqpro/video-transcript-hooks --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ntriqpro/video-transcript-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/dExkzAGkGYgKqNQq3/builds/fbbUXO9nPieJzH0c0/openapi.json
