# YouTube Transcript Scraper — $0.50/1k · Subtitles, SRT & VTT (`tidydata/youtube-transcript-scraper`) Actor

Get YouTube transcripts, subtitles and captions as clean text, timestamps, SRT or VTT. Paste video URLs, playlists, whole channels (@handle) or search terms. Manual or auto-generated captions in any language, chapters with their own text, video metadata. $0.50 per 1,000 transcripts found.

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

## Pricing

from $0.40 / 1,000 transcript extracteds

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 Transcript Scraper — Subtitles, Captions, SRT & VTT

Get the **transcript of any YouTube video** as clean, readable text — plus **timed segments, SRT and VTT subtitles, chapters with their own text** and the video's metadata. Paste single videos, **whole playlists, entire channels (@handle)** or just **search terms**, and get one tidy row per video.

**$0.50 per 1,000 transcripts** — one of the cheapest on Apify. Videos without captions are listed with the reason and are **never charged**.

- ✅ **Any input**: video links (`watch`, `youtu.be`, `shorts`, `live`, `embed`), 11-character IDs, playlists, channels (`@handle`, `/channel/UC…`, `/c/…`), channel **Shorts** and **Live** tabs, and plain **search terms**
- ✅ **Any language**: manual (human-made) captions first, auto-generated as fallback; pick your languages in order of preference or leave empty for the **original spoken language**
- ✅ **Readable text**: paragraphs (not one caption per line), or plain, or one `[mm:ss]` line per caption
- ✅ **Timed segments** `{start, duration, text}` for search, clipping, quotes and AI pipelines
- ✅ **Chapters with their own text**: each chapter's title, start, end and its part of the transcript — perfect for summaries and RAG chunks
- ✅ **SRT and WebVTT** subtitles ready to download
- ✅ **ZIP download**: one `.txt` and one `.srt` per video, free
- ✅ **Metadata**: title, channel, duration, views, description, tags, available caption languages
- ✅ **Fast and reliable**: parallel processing, automatic retries with fresh IPs; ~1 second per video
- ✅ **No API key, no login, no cookies** needed

### Who uses it

- **AI & RAG builders** — feed transcripts and chapter chunks to ChatGPT, Claude, LangChain, LlamaIndex or a vector database.
- **Content creators & marketers** — turn videos into blog posts, newsletters, quotes and social posts; research what competitors say.
- **SEO** — find the exact words top-ranking videos use; build topic clusters from a whole channel.
- **Researchers & journalists** — search what was said across hundreds of videos, with timestamps as evidence.
- **Educators & students** — notes, study guides and accessible subtitles.
- **Agencies** — monitor a channel and get every new video's transcript automatically.

### How to use it

1. **Sources**: paste one item per line, mixed as you like:
   ```
   https://www.youtube.com/watch?v=iCvmsMzlF7o
   https://youtu.be/kJQP7kiw5Fk
   @lexfridman
   https://www.youtube.com/@kurzgesagt/shorts
   https://www.youtube.com/playlist?list=PLFs4vir_WsTwEd-nJgVJCZPNL3HALHHpF
   how to make sourdough bread
   ```
2. **Max videos per source**: how many videos to take from each playlist, channel (newest first) or search.
3. Optional: **languages** (e.g. `en`, `es`, `pt-BR`), text format, SRT/VTT, chapters, ZIP.
4. Run. Download the results as JSON, CSV, Excel or HTML, or get them through the API.

### Output example

```json
{
  "status": "ok",
  "videoId": "iCvmsMzlF7o",
  "url": "https://www.youtube.com/watch?v=iCvmsMzlF7o",
  "title": "The Power of Vulnerability | Brené Brown | TED",
  "channelName": "TED",
  "channelId": "UCAuUUnT6oDeKwE6v1NGQxug",
  "durationSeconds": 1250,
  "viewCount": 25322428,
  "language": "en",
  "languageName": "English",
  "isAutoGenerated": false,
  "wordCount": 3103,
  "transcript": "So, I'll start with this: a couple years ago, an event planner called me because I was going to do a speaking event…",
  "segments": [
    { "start": 16.86, "duration": 3.46, "text": "So, I'll start with this: a couple years ago, an event planner called me" },
    { "start": 20.34, "duration": 2.05, "text": "because I was going to do a speaking event." }
  ],
  "chapters": [],
  "srt": "1\n00:00:16,860 --> 00:00:20,320\nSo, I'll start with this: a couple years ago, an event planner called me\n\n2\n…",
  "availableLanguages": [ { "code": "sq", "name": "Albanian", "autoGenerated": false }, { "code": "ar", "name": "Arabic", "autoGenerated": false }, "… 52 languages" ],
  "charged": true
}
```

For videos with chapters (here a 5-hour podcast), each chapter carries its own text:

```json
"chapters": [
  { "title": "Episode highlight", "start": 0, "end": 87, "startTime": "00:00", "text": "- There are decades where nothing happens and weeks where decades happen…" },
  { "title": "Introduction", "start": 87, "end": 176, "startTime": "01:27", "text": "- The following is a conversation with David Heinemeier Hansson, also known as DHH…" }
]
```

Videos that can't be transcribed come back as a free row with a clear `status` and `error`:

| status | meaning |
|---|---|
| `no_transcript` | the video has no captions at all (manual or auto) |
| `language_not_available` | captions exist, but not in your languages — see `availableLanguages` |
| `only_auto_captions` | you asked for human-made captions only |
| `age_restricted_or_private`, `unavailable`, `not_found` | YouTube doesn't show the video publicly |
| `failed` | YouTube kept refusing after several retries — run it again later |
| `invalid_source` | a line in *Sources* is not a YouTube link, ID or search |

Turn on **Hide videos without a transcript** to keep only successful rows.

### Pricing

**Pay per transcript: $0.0005 each ($0.50 per 1,000).** You only pay for rows with `"status": "ok"`.

| You run | You pay |
|---|---|
| 1 video | $0.0005 |
| a 50-video playlist | $0.025 |
| the last 500 videos of a channel | $0.25 |
| 10,000 transcripts | $5 |

Videos without captions, private, deleted or failed videos and invalid inputs are **free**. Higher Apify plans get an automatic discount. Set a **maximum cost per run** and the Actor stops cleanly when it is reached.

### Get new videos automatically

1. Save a task with your channel (`@channel`) and *Max videos per source* = 10.
2. Add a **schedule** (e.g. daily).
3. To keep **only new videos**, connect our [Merge, Deduplicate & Export Datasets](https://apify.com/tidydata/merge-dedupe-datasets) Actor as an integration with *Only new rows* and deduplicate by `videoId` — it can also export everything to CSV/Excel.

### Use it from code

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("tidydata/youtube-transcript-scraper").call(run_input={
    "sources": ["https://www.youtube.com/watch?v=iCvmsMzlF7o", "@lexfridman"],
    "maxVideosPerSource": 10,
    "languages": ["en"],
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item.get("wordCount"))
```

**JavaScript**

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('tidydata/youtube-transcript-scraper').call({
    sources: ['https://youtu.be/kJQP7kiw5Fk'],
    includeSrt: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].transcript);
```

It also works with **Make, Zapier, n8n**, webhooks, Google Sheets and every other Apify integration, and as a tool for AI agents through the Apify MCP server.

### FAQ

**Does it work with auto-generated captions?**
Yes. Human-made captions are preferred; if there are none, the auto-generated ones are used (`isAutoGenerated: true`). Turn on *Only human-made captions* to skip them.

**Which language will I get?**
With *Languages* empty you get the video's original spoken language. With a list (e.g. `es`, `en`) you get the first one available. Regional variants match too: `pt` finds `pt-BR`, `es` finds `es-419`.

**Can it translate captions?**
No — YouTube no longer serves its machine translations to tools like this one. You get the languages the video really has (see `availableLanguages`).

**What if a video has no captions?**
It is listed as `no_transcript` and not charged. For your own audio or video files (MP3, MP4, WAV…) you can use our [Audio & Video Transcription](https://apify.com/tidydata/audio-video-transcription) Actor.

**How many videos can I get from a channel?**
Up to 5,000 per source (newest first). Use the `/shorts` or `/streams` tab links for Shorts and live streams.

**Is the text cleaned?**
Yes: HTML entities and tags are removed, line breaks inside captions are joined, and the `paragraphs` format groups sentences into readable paragraphs at natural pauses. Sound tags like `[Music]` or `(Laughter)` are kept because they are part of the captions.

**Do I need a YouTube account, API key or proxy?**
No. Everything is included in the price.

**Is it legal?**
The Actor only reads captions that YouTube shows publicly to any visitor. Transcripts belong to their creators: use them for research, analysis, accessibility or with permission, and respect copyright and YouTube's terms when you republish content.

**Something doesn't work?**
Open an issue in the **Issues** tab with the video link — we answer fast.

# Actor input Schema

## `sources` (type: `array`):

One per line. Accepts video links (watch, youtu.be, shorts, live, embed) or 11-character video IDs, playlist links, channel links or @handles (add /shorts or /streams for those tabs), and plain search terms like 'how to make sourdough'.

## `maxVideosPerSource` (type: `integer`):

For playlists, channels and searches: how many videos to take (newest first for channels). Single video links always count as one.

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

Language codes in order of preference, e.g. en, es, de, pt-BR. Manual captions are preferred over auto-generated ones. Leave empty to get the video's original spoken language. Videos without any of these languages are listed with their available languages and are not charged.

## `textFormat` (type: `string`):

How the 'transcript' field is written. Segments with exact start times are also included unless you switch them off.

## `includeSegments` (type: `boolean`):

Adds 'segments': a list of {start, duration, text} in seconds — ideal for search, clipping and AI pipelines.

## `includeChapters` (type: `boolean`):

When the video has chapters (timestamps in the description), adds each chapter's title, start, end and its own part of the transcript.

## `includeSrt` (type: `boolean`):

Adds an 'srt' field with ready-to-use SubRip subtitles.

## `includeVtt` (type: `boolean`):

Adds a 'vtt' field with WebVTT subtitles for web players.

## `includeDescription` (type: `boolean`):

Adds the video description and keywords.

## `onlyManualCaptions` (type: `boolean`):

Skip videos that only have auto-generated captions (they are listed but not charged).

## `skipVideosWithoutTranscript` (type: `boolean`):

By default, videos without captions are listed with the reason (never charged). Turn on to keep only transcripts in the results.

## `downloadZip` (type: `boolean`):

Saves transcripts.zip (one .txt and one .srt per video) in the run's key-value store, free of charge.

## Actor input object example

```json
{
  "sources": [
    "https://www.youtube.com/watch?v=iCvmsMzlF7o"
  ],
  "maxVideosPerSource": 20,
  "languages": [],
  "textFormat": "paragraphs",
  "includeSegments": true,
  "includeChapters": true,
  "includeSrt": false,
  "includeVtt": false,
  "includeDescription": true,
  "onlyManualCaptions": false,
  "skipVideosWithoutTranscript": false,
  "downloadZip": false
}
```

# Actor output Schema

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

One row per video.

# 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 = {
    "sources": [
        "https://www.youtube.com/watch?v=iCvmsMzlF7o"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidydata/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 = { "sources": ["https://www.youtube.com/watch?v=iCvmsMzlF7o"] }

# Run the Actor and wait for it to finish
run = client.actor("tidydata/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 '{
  "sources": [
    "https://www.youtube.com/watch?v=iCvmsMzlF7o"
  ]
}' |
apify call tidydata/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tidydata/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/0rct9V9Xpnj6ISuJ6/builds/txfp1DdbTqvPbcYw5/openapi.json
