# YouTube Transcript & RAG Chunker (`leaderly_jackpine/youtube-rag-transcripts`) Actor

Get the full transcript of any YouTube video, playlist, channel or search - as plain text, SRT/VTT, or RAG-ready token-window chunks (overlap, dedup, token counts, deep links). Transcript-only or transcript + chunks, your choice. Multi-language + translation. Per-video pricing.

- **URL**: https://apify.com/leaderly\_jackpine/youtube-rag-transcripts.md
- **Developed by:** [William](https://apify.com/leaderly_jackpine) (community)
- **Categories:** AI, Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 video chunkeds

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

## YouTube Transcript & RAG Chunker

> **Turn YouTube into a vector database in one run.** Returns retrieval-ready transcript chunks **plus** SRT/VTT/TXT/JSON/Markdown — built for LLM apps, agents, knowledge bases, fine-tuning, search and accessibility. It is the only YouTube transcript actor that ships **token-window chunking with overlap, ASR dedup, per-chunk token counts and deep-link timestamps** out of the box, so you can embed every chunk without a preprocessing step.

**Best for:** RAG over video, LLM fine-tuning datasets, semantic search, content moderation, agent memory, subtitles, and accessibility. Input a video, playlist, channel or search query; get **the full transcript** of each video on its summary row, plus one self-contained row per chunk.

Turn YouTube **videos, playlists, channels and search queries** into **RAG-ready transcript chunks** and standard subtitle formats. Purpose-built for retrieval: token-window chunking with overlap, ASR boundary-reflow deduplication, per-chunk token counts, and deep-link timestamps so every chunk links back to the exact moment in the video. Also emits SRT, VTT, plain-text, JSON and Markdown.

You are **charged per successfully chunked video** (price set in the Apify Console). Videos with no captions, blocks, or failures are returned as uncharged status rows.

### Two modes

- **Transcript only** (`includeRagChunks: false`) — want just the transcript? Set this off. You get **one clean row per video** carrying the full transcript (plus title/channel/duration/etc. and optional SRT/VTT/Markdown). No chunk rows, no chunking — ideal when you simply need the text.
- **Transcript + RAG chunks** (`includeRagChunks: true`, default) — the full transcript *and* token-window chunk rows (one chunk per line, with overlap, dedup, token counts and deep links) for vector-DB / RAG ingestion.

In both modes the **full transcript is always present** on each video's summary row in the `transcript` field.

### What it does

1. Ingests video URLs, playlist URLs, channel URLs (any `@handle`, `/channel/UC...`, `/c/Name`, `/user/Name`), or free-text **search queries**.
2. For each video, calls the ANDROID YouTube Innertube `/player` endpoint (no 1.3 MB watch-page fetch) to get both captions and full metadata in one tiny POST.
3. Picks a caption track by your `languages` preference and `captionPreference` (manual vs ASR), with optional `translateTo`.
4. Fetches the `json3` caption track, rebuilds timed segments, and dedups ASR segments that repeat across boundary windows.
5. Chunks by **token window** (with overlap) or **fixed timestamp window**, counts tokens with the chosen tokenizer, and emits the formats you requested.

### Why it is different

The chunking surface is the product. Most transcript actors hand you one big text blob; this one hands you retrieval primitives:

- Token-window chunking with configurable overlap (carries context across chunk boundaries).
- ASR boundary-reflow deduplication (YouTube auto captions re-emit text at window edges; we collapse it).
- Per-chunk `tokenCount` (o200k\_base / cl100k\_base) and `wordCount` so you can budget embeddings/context.
- Per-chunk `deepLink` (`https://youtu.be/<id>?t=<sec>s`) so a retrieved chunk can cite its source moment.
- Optional SRT / VTT / TXT / Markdown attached to each video summary for non-RAG use cases.

### Input fields

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | string\[] | *(required)* | Video / playlist / channel / search URLs. |
| `searchQueries` | string\[] | `[]` | Free-text queries; each is run and result videos enqueued. |
| `languages` | string\[] | `["en"]` | Preferred caption languageCodes in priority order. |
| `captionPreference` | enum | `manual` | `manual` prefer human captions; `auto` prefer ASR. |
| `translateTo` | string | *(none)* | Optional `&tlang` translation languageCode. |
| `chunkSizeTokens` | int | `512` | Target tokens per chunk (128-8192), tokenWindow mode. |
| `chunkOverlapTokens` | int | `64` | Overlap tokens per chunk (0-512). |
| `chunkingMode` | enum | `tokenWindow` | `tokenWindow` or `timestampWindow`. |
| `timestampWindowSeconds` | int | `60` | Window length (10-600), timestampWindow mode. |
| `tokenizerModel` | enum | `o200k_base` | `o200k_base` (GPT-4o/4.1/o-series) or `cl100k_base` (GPT-4/3.5). |
| `outputFormats` | string\[] | `["chunkRows","json"]` | One or more of: `chunkRows`, `json`, `srt`, `vtt`, `txt`, `markdown`. |
| `maxVideos` | int | `50` | Hard cap on videos processed across all sources (1-1000). |
| `proxyConfiguration` | proxy | residential US | Apify Proxy config. Residential US is strongly recommended. |

### Output

Three row shapes land in the default dataset:

**Flat chunk row** (`type: "chunk"`, free, emitted when `chunkRows` is requested):

- `chunkId`, `videoId`, `index`, `totalChunks`
- `startMs`, `endMs`, `text`, `tokenCount`, `wordCount`
- `deepLink` (`https://youtu.be/<videoId>?t=<seconds>s`)
- `videoTitle`, `channelName`, `channelId`, `language`, `isAsr`, `captionLanguage`, `sourceUrl`

**Video summary row** (`type: "video"`, charged, emitted for every chunked video):

- `videoId`, `title`, `channelName`, `channelId`, `publishedAt` (null on the ANDROID client), `durationSec`
- `description` (truncated to 2000 chars), `keywords`, `viewCount`
- `language`, `isAsr`, `captionLanguage`, `sourceUrl`
- `totalChunks`, `totalTokens`, `totalWords`
- `chunks` (nested, present unless `chunkRows` is also requested, in which case chunks travel as flat rows)
- Optional `srt`, `vtt`, `txt`, `markdown` when those formats are requested

**Status row** (`type: "status"`, free): `no_captions` / `blocked` / `failed` / `unsupported_url`, with `videoId`, `url`, `reason`.

### Example input

```json
{
  "startUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf",
    "https://www.youtube.com/@mkbhd/videos"
  ],
  "searchQueries": ["apify actor tutorial"],
  "languages": ["en"],
  "captionPreference": "manual",
  "chunkSizeTokens": 512,
  "chunkOverlapTokens": 64,
  "chunkingMode": "tokenWindow",
  "tokenizerModel": "o200k_base",
  "outputFormats": ["chunkRows", "json", "srt"],
  "maxVideos": 50,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }
}
```

### Pricing

Charged per successfully chunked video (one `type: "video"` row per video). Set the USD unit price in the Apify Console; the actor honours `ACTOR_MAX_TOTAL_CHARGE_USD` to cap spend. Flat chunk rows and status rows are free.

### Important notes

- **Token counts are estimates for non-OpenAI models.** `o200k_base` matches GPT-4o / 4.1 / o-series; `cl100k_base` matches GPT-4 / 3.5. For Claude, embedding models, or other tokenisers, expect 5-15% drift. Size your chunks with headroom.
- **Residential US proxy is the default.** Datacenter egress can be bot-flagged and silently return no `captionTracks`; the actor detects non-OK `playabilityStatus` and retires the session.
- **Known limitations:**
  - **Channel URLs return ~30 latest videos.** Deep history pagination via `/browse` continuation is unreliable and intentionally not implemented. Use playlist URLs for exhaustive channel crawls.
  - **Search returns ~20 results per query** (the first results page).
  - **Videos without captions** produce a free `no_captions` status row, not a charged video row.
  - `publishedAt` is `null` on every video summary: the ANDROID `/player` client omits the upload date.
- The actor does **not** store or download audio/video; it returns transcript text only.

### Changelog

See `CHANGELOG.md`.

# Actor input Schema

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

YouTube video (youtube.com/watch?v=... or youtu.be/...), playlist (youtube.com/playlist?list=...), channel (youtube.com/@handle, /channel/UC..., /c/Name or /user/Name, with or without /videos) or search (youtube.com/results?search\_query=) URLs.

## `searchQueries` (type: `array`):

Free-text search queries; each is run on YouTube and its result videos are enqueued (capped by maxVideos).

## `languages` (type: `array`):

Preferred caption languageCodes in priority order (e.g. \['en','en-US']). The first match present on the video wins.

## `captionPreference` (type: `string`):

manual = prefer human captions, fall back to auto-generated (ASR); auto = prefer ASR.

## `translateTo` (type: `string`):

Optional translation languageCode appended as \&tlang to the caption baseUrl (e.g. 'es'). When set, the chosen track is translated into this language.

## `chunkSizeTokens` (type: `integer`):

Target maximum tokens per chunk in tokenWindow mode (128-8192). Chunks are segment-aligned so a chunk may slightly exceed this when a single caption segment is larger.

## `chunkOverlapTokens` (type: `integer`):

Overlap tokens carried into the next chunk in tokenWindow mode (0-512). Must be smaller than chunk size.

## `chunkingMode` (type: `string`):

tokenWindow = greedily pack segments up to chunk size with overlap; timestampWindow = one chunk per fixed-length time window.

## `timestampWindowSeconds` (type: `integer`):

Length of each time window in timestampWindow mode (10-600).

## `tokenizerModel` (type: `string`):

Tokenizer used for token counts. o200k\_base matches GPT-4o/4.1/o-series; cl100k\_base matches GPT-4/3.5. Note: counts are estimates for non-OpenAI models (Claude/embeddings may differ 5-15%).

## `outputFormats` (type: `array`):

What to emit per video. chunkRows = flat chunk rows (one per line, free, ideal for JSONL/RAG ingestion); json = per-video summary row with nested chunks (charged); srt/vtt/txt = subtitle/plain-text transcript attached to the summary row; markdown = transcript with timestamp headings + deep links.

## `includeRagChunks` (type: `boolean`):

ON (default) = transcript + RAG-ready token-window chunks (flat chunk rows per video). OFF = transcript-only mode: one clean row per video with the full transcript (no chunk rows, no chunking). Use OFF when you just want the transcript text of each video.

## `maxVideos` (type: `integer`):

Hard cap on the number of videos processed across all sources (1-1000). Listing videos beyond this are skipped.

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

Apify Proxy. Residential with US country pin is the default: datacenter egress can be bot-flagged and silently return no captionTracks.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "languages": [
    "en"
  ],
  "captionPreference": "manual",
  "chunkSizeTokens": 512,
  "chunkOverlapTokens": 64,
  "chunkingMode": "tokenWindow",
  "timestampWindowSeconds": 60,
  "tokenizerModel": "o200k_base",
  "outputFormats": [
    "chunkRows",
    "json"
  ],
  "includeRagChunks": true,
  "maxVideos": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `results` (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 = {
    "startUrls": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    ],
    "languages": [
        "en"
    ],
    "captionPreference": "manual",
    "chunkingMode": "tokenWindow",
    "tokenizerModel": "o200k_base",
    "outputFormats": [
        "chunkRows",
        "json"
    ],
    "includeRagChunks": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("leaderly_jackpine/youtube-rag-transcripts").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": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
    "languages": ["en"],
    "captionPreference": "manual",
    "chunkingMode": "tokenWindow",
    "tokenizerModel": "o200k_base",
    "outputFormats": [
        "chunkRows",
        "json",
    ],
    "includeRagChunks": True,
}

# Run the Actor and wait for it to finish
run = client.actor("leaderly_jackpine/youtube-rag-transcripts").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 '{
  "startUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "languages": [
    "en"
  ],
  "captionPreference": "manual",
  "chunkingMode": "tokenWindow",
  "tokenizerModel": "o200k_base",
  "outputFormats": [
    "chunkRows",
    "json"
  ],
  "includeRagChunks": true
}' |
apify call leaderly_jackpine/youtube-rag-transcripts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=leaderly_jackpine/youtube-rag-transcripts",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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