# YouTube Transcript Scraper (`lergassy/youtube-transcript-scraper`) Actor

Get YouTube transcripts with timecodes, chapters and video metadata. Works with single videos, playlists and whole channels, returns SRT or WebVTT subtitles, and splits transcripts into RAG chunks that keep their timecodes. Export data, run via API, or schedule runs.

- **URL**: https://apify.com/lergassy/youtube-transcript-scraper.md
- **Developed by:** [Matvey](https://apify.com/lergassy) (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 $2.80 / 1,000 video transcribeds

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?

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

Get **YouTube transcripts** with timecodes, chapters and full video metadata. Point it at a video, a playlist or an entire channel. Returns plain text, timed segments, ready-made SRT or WebVTT subtitle files, and retrieval chunks that keep the moment in the video where each passage was said. No API key, no cookies, no login.

### What is YouTube Transcript Scraper?

YouTube Transcript Scraper turns spoken video into structured text you can search, quote and feed to a model. Give it links, get one row per video with the transcript and everything around it: title, channel, publication date, duration, view count, chapters and the languages the video has captions in.

The thing most transcript tools drop is *where* something was said. Here every caption line keeps its start time, every chapter is returned with its boundaries, and each retrieval chunk carries its own timecode and chapter title — so an answer built on this data can point at minute 14:32 instead of quoting a wall of text.

| What you give it | What you get back |
| --- | --- |
| A video URL or bare video id | Transcript, segments, chapters, metadata |
| A playlist URL | Every video in it, up to your limit |
| A channel URL | The channel's videos, newest first |
| `chunkForRag: true` | Chunks with chapter titles and timecodes |
| `subtitleFormat: srt` | A subtitle file ready to attach |

### What data can YouTube Transcript Scraper extract?

| Field | Type | Example |
| --- | --- | --- |
| `videoId` | string | `dQw4w9WgXcQ` |
| `url` | string | `https://www.youtube.com/watch?v=dQw4w9WgXcQ` |
| `title` | string | `Rick Astley - Never Gonna Give You Up` |
| `channel` / `channelId` / `channelUrl` | string | `Rick Astley` |
| `publishedAt` | string | `2009-10-25` |
| `durationSeconds` | integer | `213` |
| `viewCount` / `likeCount` / `commentCount` | integer | `1663000000` |
| `description` | string | Full description, when requested |
| `tags` / `categories` | array | `["rick astley", "music"]` |
| `thumbnail` | string | Thumbnail URL |
| `isLive` | boolean | `false` |
| `language` | string | `en`, or a track label such as `en-nP7-2PuUl7o` |
| `isAutoGenerated` | boolean | `false` for human-written subtitles |
| `availableLanguages` | array | `["en", "de", "ja", "pt"]` |
| `transcript` | string | `We're no strangers to love…` |
| `wordCount` / `charCount` / `segmentCount` | integer | `481` / `2510` / `60` |
| `segments` | array | `[{"start": 0.59, "duration": 5, "text": "…"}]` |
| `chapters` | array | `[{"title": "Intro", "start": 0, "end": 47}]` |
| `chunks` | array | `[{"index": 0, "chapter": "Intro", "start": 0.59, "startTimecode": "00:00:00", "text": "…"}]` |
| `subtitles` | string | A complete SRT or WebVTT file |
| `status` / `errorCode` / `errorMessage` | string | `ok`, or why a video was skipped |
| `scrapedAt` | string | `2026-09-05T10:31:02+00:00` |

### How much does it cost to scrape YouTube transcripts?

| Event | Price | When it is charged |
| --- | --- | --- |
| Video transcribed | $0.004 | Per video whose transcript is returned |
| Video listed | $0.0002 | Per video found inside a channel or playlist |

**Videos without captions are never charged.** Neither are private, removed or age-restricted videos: they come back as `error` rows with a reason, at no cost.

| Job | Cost |
| --- | --- |
| 1,000 videos | $4.00 |
| A 200-video channel | $0.84 |
| 50 videos from each of 20 channels | $4.20 |
| One long podcast episode | $0.004 |

Comparable transcript Actors charge $5 to $9 per 1,000 videos. The Apify Free plan includes $5 of monthly usage, which is about **1,200 videos** before you pay anything.

### How to get a YouTube transcript

1. Click **Try for free** and sign in to Apify.
2. Paste video, playlist or channel links into **Videos, playlists or channels**.
3. Leave the language as `en`, or set the two-letter code you need.
4. Switch on **Split into RAG chunks** if the text is going into a vector database, or pick a **Subtitle file** format if you need SRT or WebVTT.
5. Press **Start**, then read the **Output** tab or export as JSON, CSV or Excel.

### ⬇️ Input

![YouTube Transcript Scraper input: video, playlist and channel URLs, language, RAG chunks and subtitle format](https://raw.githubusercontent.com/lergassy/apify-actor-assets/main/youtube-transcript-scraper/youtube-transcript-scraper-input-form.png)

```json
{
  "videos": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://www.youtube.com/playlist?list=PLbpi6ZahtOH6Blw3RGYpWkSByi_T7Rygb",
    "https://www.youtube.com/@veritasium"
  ],
  "language": "en",
  "allowAutoGenerated": true,
  "includeSegments": true,
  "chunkForRag": false,
  "maxVideosPerChannel": 25
}
```

#### What counts as an input

Video URLs, bare 11-character video ids, `youtu.be` short links, Shorts and live URLs, playlist URLs, and channel URLs in every form (`/@handle`, `/channel/UC…`, `/c/name`). Playlists and channels are expanded automatically, up to **Max videos per channel or playlist**.

#### Languages

`language` takes a two-letter code. YouTube labels many tracks `en-nP7-2PuUl7o` rather than plain `en` — those count as English here, which is why videos other tools report as "no captions" work fine. Human-written subtitles are preferred; **Use auto-generated captions when needed** decides whether YouTube's automatic ones are acceptable as a fallback, and `isAutoGenerated` tells you which you got.

#### RAG chunks with timecodes

With `chunkForRag: true` the transcript is split into chunks that break on chapter boundaries and sentence ends rather than on a raw character count. Each chunk carries the chapter it belongs to and the timecode where it starts:

```json
{
  "index": 3,
  "chapter": "How the engine works",
  "start": 872.5,
  "end": 954.1,
  "startTimecode": "00:14:32",
  "text": "The compression stage is where most of the loss happens…",
  "charCount": 1180
}
```

`chunkOverlapSeconds` repeats a few seconds of the previous chunk at the start of the next one, which helps when a sentence straddles a boundary.

#### Subtitle files

`subtitleFormat` returns a complete `SRT` or `WebVTT` file in the `subtitles` field, timings included, ready to save next to the video.

### ⬆️ Output

![YouTube Transcript Scraper output: one row per video with channel, duration, language, word count and timed segments](https://raw.githubusercontent.com/lergassy/apify-actor-assets/main/youtube-transcript-scraper/youtube-transcript-scraper-output-table.png)

```json
{
  "videoId": "dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Video)",
  "channel": "Rick Astley",
  "publishedAt": "2009-10-25",
  "durationSeconds": 213,
  "language": "en",
  "isAutoGenerated": false,
  "availableLanguages": ["en", "de", "ja", "pt"],
  "transcript": "We're no strangers to love. You know the rules and so do I…",
  "wordCount": 481,
  "segmentCount": 60,
  "segments": [{ "start": 0.59, "duration": 5, "text": "We're no strangers to love" }],
  "chapters": [],
  "status": "ok",
  "scrapedAt": "2026-09-05T10:31:02+00:00"
}
```

#### Error rows

| `errorCode` | Meaning |
| --- | --- |
| `no-captions` | The video has no captions in the language you asked for; `availableLanguages` lists what it does have |
| `video-unavailable` | Removed, or the id does not exist |
| `private-video` | Private or members-only |
| `age-restricted` | Behind an age gate |
| `rate-limited` | YouTube throttled the run after several retries |
| `invalid-input` | Not a YouTube video, playlist or channel |

### Use cases

#### Feeding video into a RAG pipeline

Chunks with timecodes let a retrieval answer cite the exact moment, so a support bot trained on tutorial videos can link to 14:32 rather than to the video as a whole.

#### Content research and repurposing

Pull a competitor's channel, read what they cover, and turn talks into articles, newsletters or show notes.

#### Subtitles and translation workflows

Take the SRT out, translate it, put it back. Auto-generated captions are marked, so you know which files need a human pass.

#### Search across a channel

Transcribe a whole channel once, index the text, and search hundreds of hours of video by phrase.

#### Dataset building

Transcripts with duration, view count and publication date make a clean training or analysis set, one row per video.

### Integrations

- **API**: `POST https://api.apify.com/v2/acts/lergassy~youtube-transcript-scraper/runs`
- **Python**: `ApifyClient(token).actor('lergassy/youtube-transcript-scraper').call(run_input={'videos': ['dQw4w9WgXcQ']})`
- **JavaScript**: `await client.actor('lergassy/youtube-transcript-scraper').call({ videos: ['dQw4w9WgXcQ'] })`
- **n8n, Make, Zapier, Google Sheets, Airtable**: run the Actor and map the dataset onward.
- **MCP**: available through the Apify MCP server as a callable tool.
- **Webhooks**: fire a webhook when a run finishes.

### 🤖 For AI agents and LLM apps

```json
{ "videos": ["dQw4w9WgXcQ"], "language": "en", "chunkForRag": true }
```

- One row per video; `status` is `ok` or `error`, so a skipped video needs no log parsing.
- `transcript` is the field to summarise; `chunks` is the field to embed.
- Every chunk carries `startTimecode` and `chapter`, so an answer can cite where in the video it came from.
- `isAutoGenerated` warns when the text is machine-heard rather than human-written.
- Videos without captions are never charged, so agent retries stay cheap.

### ❓ FAQ

#### Is it legal to scrape YouTube transcripts?

The Actor reads captions that YouTube publishes openly on public video pages, with no login. What you may do with that text depends on the video's copyright and on YouTube's terms, so check both before republishing. This is not legal advice.

#### Do I need an API key or cookies?

No. There is nothing to configure beyond the links.

#### Why does it use a proxy by default?

YouTube refuses data-centre addresses outright — in testing, nine requests in ten came back with "Sign in to confirm you're not a bot". The Actor uses residential proxies with a fresh address per video, which measured a 95% success rate. You can override the proxy setting, but success will drop sharply.

#### Does it work with videos that have no subtitles?

No. If a video has no captions at all, nothing exists to fetch, and the row comes back as `no-captions` at no charge. For those, transcribe the audio instead.

#### Can it do whole channels?

Yes. Pass the channel URL and set **Max videos per channel or playlist**. Listing a video costs $0.0002; only the ones that produce a transcript cost the full price.

#### Can I use it with the Apify API or an MCP server?

Yes to both, like any Apify Actor.

### Your feedback

Missing a field or a format? Open an issue on the **Issues** tab — issues are answered quickly.

### You might also like

| Actor | What it does |
| --- | --- |
| [Document Text Extractor](https://apify.com/lergassy/document-text-extractor) | PDF, Word, Excel and PowerPoint to Markdown, tables and RAG chunks |
| [OCR Text Extractor](https://apify.com/lergassy/ocr-text-extractor) | Images and scanned PDFs to text with confidence scores |
| [Trustpilot Reviews API](https://apify.com/lergassy/trustpilot-reviews-api) | Trustpilot reviews, ratings and company replies |
| [Software Reviews Scraper](https://apify.com/lergassy/software-reviews-scraper) | Capterra, Software Advice, GetApp and TrustRadius in one schema |

# Actor input Schema

## `videos` (type: `array`):

YouTube video URLs, bare video IDs, playlist URLs or channel URLs. Playlists and channels are expanded into their videos automatically.

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

Two-letter language code, for example <code>en</code>, <code>de</code>, <code>es</code>. Tracks labelled <code>en-abc123</code> count as English too.

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

Fall back to YouTube's automatic captions when the video has no human-written subtitles in that language.

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

Return every caption line with its start time and duration, alongside the full transcript.

## `chunkForRag` (type: `boolean`):

Split the transcript into retrieval chunks. Each chunk carries its chapter title and the timecode where it starts, so an answer can cite the moment in the video.

## `chunkSize` (type: `integer`):

Target size of one chunk. Chunks break on chapter boundaries and sentence ends, so real sizes vary.

## `chunkOverlapSeconds` (type: `integer`):

How many seconds of the previous chunk to repeat at the start of the next one.

## `subtitleFormat` (type: `string`):

Also return a ready-made subtitle file as text.

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

Add the full video description to each row.

## `maxVideosPerChannel` (type: `integer`):

How many videos to take from each channel or playlist you pass in.

## `maxConcurrency` (type: `integer`):

How many videos to read at the same time.

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

Leave as is. YouTube refuses data-centre addresses, so the Actor uses residential proxies with a fresh address per video.

## Actor input object example

```json
{
  "videos": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://www.youtube.com/watch?v=jNQXAC9IVRw"
  ],
  "language": "en",
  "allowAutoGenerated": true,
  "includeSegments": true,
  "chunkForRag": false,
  "chunkSize": 1200,
  "chunkOverlapSeconds": 0,
  "subtitleFormat": "none",
  "includeDescription": false,
  "maxVideosPerChannel": 25,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `transcripts` (type: `string`):

Dataset with one row per video.

## `transcriptsInConsole` (type: `string`):

Browse the transcripts in the Apify Console.

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

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

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

```

## MCP server setup

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