# YouTube Transcript Scraper - Bulk & Whole Channels (`gganbukim/youtube-transcript-scraper`) Actor

Extract transcripts from thousands of YouTube videos in one run. Paste video URLs, a channel, or a playlist. Clean text, timestamped segments, SRT and WebVTT subtitles, or RAG-ready chunks. Any language, human or auto captions, plus video metadata. $2 per 1,000; videos without captions are free.

- **URL**: https://apify.com/gganbukim/youtube-transcript-scraper.md
- **Developed by:** [DONGMIN KIM](https://apify.com/gganbukim) (community)
- **Categories:** AI, Videos, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 transcript delivereds

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/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 Scraper — Bulk Subtitles to Text, SRT, VTT & RAG Chunks

Extract transcripts from **thousands of YouTube videos in one run**. Paste video URLs, a channel, or a playlist — get back clean text, timestamped segments, SRT/VTT subtitle files, or pre-chunked passages ready for embeddings. Video metadata is included in every row at no extra cost.

Built for people who hit the wall with other transcript scrapers: **one URL at a time, silent failures when YouTube throttles, and no metadata.**

***

### What makes this one different

| | This actor | Typical transcript scraper |
|---|---|---|
| **Input** | Unlimited URLs + whole channels + playlists in one run | One video URL per run |
| **Throttling** | Datacenter → residential proxy escalation, per-video IP sessions | Fails, or silently returns nothing |
| **Metadata** | Title, channel, views, duration, publish date, keywords, thumbnail — free | Sold separately, or missing |
| **RAG output** | Merged chunks with timestamps + configurable overlap | Raw 2-second caption cues |
| **Languages** | Priority list, human tracks preferred over auto-generated | First track found |
| **Failures** | Row with a readable `error`, and you are never charged for it | Charged anyway, or the run dies |

#### Why the throttling part matters

YouTube's caption host (`youtube.com/api/timedtext`) rate-limits **per IP address**, and independently of the rest of the API. Once an IP is throttled, every caption format and every header combination keeps returning HTTP 429 — we measured this: 15 request variants, all blocked, for over 40 minutes on the same IP.

Most scrapers treat that as "retry and hope". This one treats a 429 as *burn this IP* and moves to a fresh proxy session. It also starts on **cheap datacenter proxies** and only escalates to residential once datacenter is provably blocked — which is exactly why it can be priced below the alternatives.

***

### Input

Paste anything YouTube-shaped into **YouTube URLs**:

```jsonc
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=8S0FDjFBj8o",   // watch URL
    "https://youtu.be/jNQXAC9IVRw",                   // short link
    "https://www.youtube.com/shorts/abcdefghijk",     // Shorts
    "dQw4w9WgXcQ",                                    // bare video ID
    "@veritasium",                                    // whole channel
    "https://www.youtube.com/playlist?list=PLZHQ..."  // whole playlist
  ],
  "maxVideos": 500,
  "languages": ["en", "es"],
  "outputFormat": "chunks",
  "chunkMaxChars": 1200,
  "chunkOverlapChars": 100
}
```

Channels and playlists are expanded to their videos automatically, up to **Max videos**.

#### Key settings

- **Preferred languages** — ISO-639-1 codes in priority order. A human-made track always beats an auto-generated one in the same language.
- **Allow auto-generated captions** — turn off if you only want reviewed subtitles.
- **Output format** — `text`, `chunks`, `segments`, `srt`, `vtt`, or `all`.
- **Chunk size / overlap** — only used by `chunks`. Caption cues are ~2 seconds long and useless for embeddings; this merges them into passages.
- **Concurrency** — default 10. Raise for speed.

***

### Output

One row per video:

```json
{
  "videoId": "8S0FDjFBj8o",
  "url": "https://www.youtube.com/watch?v=8S0FDjFBj8o",
  "title": "The Danger of Silence",
  "channelName": "TEDx Talks",
  "channelId": "UCsT0YIqwnpJCM-mx7-gSA4Q",
  "durationSeconds": 356,
  "viewCount": 15641909,
  "publishedAt": "2014-03-07",
  "keywords": ["poetry", "education"],
  "thumbnailUrl": "https://i.ytimg.com/vi/8S0FDjFBj8o/maxresdefault.jpg",
  "language": "en",
  "languageName": "English",
  "isAutoGenerated": false,
  "segmentCount": 128,
  "wordCount": 1043,
  "transcript": "Hear that? That is the sound of ..."
}
```

With `outputFormat: "chunks"` you also get:

```json
"chunks": [
  { "start": 0.0,   "end": 58.4,  "text": "Hear that? ..." },
  { "start": 55.1,  "end": 121.7, "text": "...continues here" }
]
```

Videos with no captions come back as a row with `transcript: null` and a readable `error` — **and are never billed**.

***

### Pricing

Pay per event. **Beyond $0.00004 for starting a run — the platform's $0.00001 minimum, charged once per GB — you are only charged for a transcript that is actually delivered.** Videos without captions, throttled requests, and failed rows cost you nothing.

Run it on a channel of 500 videos and you pay for the transcripts you get back, not for the attempts.

***

### Common uses

- **RAG / AI knowledge bases** — `chunks` format drops straight into a vector store.
- **Content repurposing** — turn a back catalogue into blog posts, newsletters, show notes.
- **Competitor & market research** — transcribe a competitor's whole channel and search it.
- **SEO** — extract the language your audience actually uses, at scale.
- **Subtitle files** — bulk SRT/VTT export for re-uploading or translating.
- **Datasets** — build training or analysis corpora with metadata attached.

***

### FAQ

**Does this need a YouTube API key?**
No. The official Data API will not return captions for videos you do not own; this does not use it.

**What if a video has no captions?**
You get a row with `error` explaining why, plus `availableLanguages` when there were tracks in other languages. You are not charged.

**Can I get auto-translated captions?**
Not currently. YouTube removed the `tlang` translation parameter from the caption endpoint. Pull the original language and translate downstream.

**How fast is it?**
Concurrency 10 by default. A 500-video channel typically finishes in a few minutes.

**Can I run it on a schedule?**
Yes — use Apify Schedules, or call it from the API. It is also available over MCP for AI agents.

**Is scraping YouTube transcripts legal?**
This reads publicly available caption data, the same data the YouTube web player requests. You are responsible for how you use the output, including copyright in the underlying content.

***

### Integrations

Works with Apify's standard integrations: webhooks, Zapier, Make, n8n, Google Sheets, Airtable, LangChain, and the Apify MCP server for AI agents. Every run's dataset is available as JSON, CSV, Excel or XML via the API.

# Actor input Schema

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

Videos, channels or playlists. Paste any mix of: watch URLs, youtu.be links, /shorts/, /embed/, bare 11-character video IDs, @handles, /channel/UC…, or playlist URLs. Channels and playlists are expanded into their videos automatically.

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

Hard cap on how many videos this run will process, counting videos pulled out of channels and playlists. Leave empty for no cap.

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

ISO-639-1 codes in priority order, e.g. en, es, ko. The first language the video actually has is used. A human-made track always wins over an auto-generated one in the same language.

## `allowAutoGenerated` (type: `boolean`):

Fall back to YouTube's speech-recognition captions when no human-made track exists. Turn this off if you only want reviewed subtitles.

## `anyLanguageFallback` (type: `boolean`):

If none of your preferred languages exist, take whatever track the video does have instead of returning nothing.

## `outputFormat` (type: `string`):

text = one clean paragraph string. chunks = merged passages sized for RAG/embeddings. segments = raw timed cues. srt / vtt = subtitle files. all = every field at once.

## `chunkMaxChars` (type: `integer`):

Only used by the "chunks" format. Caption cues are ~2 seconds long and useless for embeddings; this merges them into passages of about this length.

## `chunkOverlapChars` (type: `integer`):

Repeat this much of the previous chunk at the start of the next one, so a sentence split across a boundary still embeds well.

## `includeMetadata` (type: `boolean`):

Add title, channel, view count, duration, publish date, keywords and thumbnail to every row. Free — it arrives in the same request as the transcript.

## `includeEmptyResults` (type: `boolean`):

Emit a row with an error field for videos that have no usable transcript, instead of skipping them silently. You are never charged for these rows.

## `concurrency` (type: `integer`):

How many videos to fetch in parallel. Raise it for speed, lower it if you see throttling on a small proxy pool.

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

Leave the default. YouTube throttles caption downloads per IP, so the actor starts on cheap datacenter proxies and only escalates to residential when it actually gets blocked — that escalation is what keeps the price low.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=8S0FDjFBj8o"
  ],
  "maxVideos": 100,
  "languages": [
    "en"
  ],
  "allowAutoGenerated": true,
  "anyLanguageFallback": true,
  "outputFormat": "text",
  "chunkMaxChars": 1200,
  "chunkOverlapChars": 0,
  "includeMetadata": true,
  "includeEmptyResults": true,
  "concurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per video: the transcript in the formats you asked for, the caption track it came from, and the video metadata.

## `runSummary` (type: `string`):

Counts for this run: rows delivered, rows filtered, items that failed, the proxy tier used, and whether the run stopped at its charge limit.

# 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/watch?v=8S0FDjFBj8o"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("gganbukim/youtube-transcript-scraper").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/watch?v=8S0FDjFBj8o"] }

# Run the Actor and wait for it to finish
run = client.actor("gganbukim/youtube-transcript-scraper").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/watch?v=8S0FDjFBj8o"
  ]
}' |
apify call gganbukim/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gganbukim/youtube-transcript-scraper"
        }
    }
}

```

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/YxzeF26oitfdz9zyP/builds/kVVeKaLfsb0aW4pRm/openapi.json
