# YouTube Transcript Scraper: Captions, SRT & Text (`stratumics/youtube-transcript-scraper`) Actor

Get YouTube transcripts and captions as plain text, timed segments, SRT or WebVTT, from video links, whole channels or playlists, in any language YouTube offers. Videos without captions are free.

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

## Pricing

from $0.50 / 1,000 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 Transcript Scraper** gets the **transcripts and captions of YouTube videos** as plain text, timed segments, **SRT or WebVTT subtitles**, from single video links, whole channels or playlists. It reads the captions YouTube itself shows (creator-made or automatic) in any language the video offers, and returns one clean row per video with the title, channel, publish date, duration and language.

Use it as a **YouTube transcript API** without a YouTube API key or login: paste links, press Start, and download the results as JSON, CSV or Excel, or feed them straight into your AI tools. Videos without captions are saved with a clear status and are not charged.

### Why use this YouTube Transcript Scraper?

- **Links, channels and playlists in one run.** Paste watch, youtu.be, Shorts or live links, @handles or channel links, and playlist links. Channels and playlists are read up to the number of videos you choose.
- **The right language by default.** Without settings you get each video in its original spoken language. YouTube adds automatic captions in dubbed languages to many videos; the scraper finds the language that was really spoken instead of taking the first track listed.
- **Your languages, in your order.** List `es`, `pt-BR`, `en` and each video comes in the first one it has. `en` also matches `en-GB` and `en-US`.
- **Creator captions first.** When a language has both creator-made and automatic captions, you get the creator's, or the automatic ones if you prefer.
- **Five output formats.** Plain text, timed segments (start, duration, text), both, a ready SRT file or a WebVTT file.
- **Built for AI pipelines.** Every row has the full text in one field, the timed segments, a word count that works for Japanese, Chinese and Thai too, and the language code, so it drops into chunking, summaries and search without clean-up.
- **You pay only for transcripts.** Videos without captions, removed or private videos and failed requests are stored free, with the reason in `statusMessage`.
- **No proxy setup.** YouTube shows captions to Apify's servers only through a proxy, and the scraper uses Apify datacenter proxy (part of every Apify plan) for exactly those requests by itself.

### What data do you get?

| Field | Example | Notes |
|---|---|---|
| `videoId`, `url`, `title` | UF8uR6Z6KLc, Steve Jobs' 2005 Stanford Commencement Address | Shorts get a /shorts/ link |
| `channelName`, `channelHandle`, `channelId`, `channelUrl` | Stanford, @stanford | Who posted it |
| `publishedAt`, `durationSeconds`, `viewCount` | 2008-03-07, 904, 49272961 | Publish date, length in seconds, exact views |
| `status`, `statusMessage` | ok | `ok`, `no_captions`, `unavailable` or `failed`, with the reason |
| `language`, `languageName`, `isAutoGenerated` | en, English, false | The track you got |
| `isRequestedLanguage` | true | False when none of your languages existed and you got the original one |
| `availableLanguages` | `[{"code": "ja", "name": "Japanese", "isAutoGenerated": false}]` | Every caption track the video has |
| `transcriptText` | This program is brought to you by Stanford University... | The whole transcript as one text |
| `segments` | `[{"start": 7.47, "duration": 2.899, "text": "..."}]` | Timed lines, in seconds |
| `srt`, `vtt` | `1\n00:00:07,470 --> 00:00:10,369\n...` | Ready subtitle files, when you pick those formats |
| `wordCount`, `segmentCount` | 2301, 244 | Size of the transcript |
| `sourceType`, `sourceInput`, `position` | channel, @stanford, 12 | Which input the video came from, and its place in the channel or playlist |
| `thumbnailUrl`, `scrapedAt` | | Thumbnail link and the time the row was saved |

### How to get YouTube transcripts

1. Open the Actor and paste one or more video links in **Video links**, or add **Channels** or **Playlist links**.
2. For channels and playlists, set **Maximum videos per channel or playlist** (50 by default).
3. Optional: list **Preferred languages**, turn off **Prefer captions written by the creator**, or pick an **Output format**.
4. Press **Start**. Each transcript takes 10 to 30 seconds and the scraper works on 10 videos at once, so 1,000 videos take about 20 to 40 minutes.
5. Download the dataset as JSON, CSV or Excel, or read it through the API.

### How much does it cost?

You pay per transcript saved, and Apify bills it with your usage:

| Apify plan | Price per 1,000 transcripts |
|---|---|
| Free | $1.00 |
| Starter | $0.80 |
| Scale | $0.60 |
| Business | $0.50 |

So **1,000 transcripts cost $1.00** on the Free plan, and a channel's 200 newest videos cost at most $0.20. Rows without a transcript are free. Each run also has a start fee of $0.0005. The Free plan's $5 monthly credit covers about 5,000 transcripts. You can set a maximum cost per run in the run options: the scraper stops at that amount and never charges past it.

### Input

Three video links, with text and timed segments (the run behind the output below):

```json
{
    "videoUrls": [
        "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
        "https://www.youtube.com/watch?v=VyICtBxmkWo",
        "https://www.youtube.com/watch?v=D-WSODwniOc"
    ],
    "outputFormat": "both"
}
```

The 20 newest videos of a channel as plain text, in English where it exists, else Spanish, else the original language:

```json
{
    "channels": ["@stanford"],
    "maxVideos": 20,
    "languages": ["en", "es"],
    "outputFormat": "text"
}
```

### Output

Three real rows, trimmed: long text, segments and language lists are shortened, and the last two show only some fields.

```json
[
    {
        "videoId": "UF8uR6Z6KLc",
        "url": "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
        "title": "Steve Jobs' 2005 Stanford Commencement Address",
        "channelName": "Stanford",
        "channelId": "UC-EnprmCZ3OXyAoG7vjVNCA",
        "channelHandle": "@stanford",
        "channelUrl": "https://www.youtube.com/@stanford",
        "publishedAt": "2008-03-07",
        "durationSeconds": 904,
        "viewCount": 49272961,
        "thumbnailUrl": "https://i.ytimg.com/vi/UF8uR6Z6KLc/hqdefault.jpg",
        "status": "ok",
        "statusMessage": null,
        "language": "en",
        "languageName": "English - English",
        "isAutoGenerated": false,
        "isRequestedLanguage": null,
        "availableLanguages": [
            { "code": "ar", "name": "Arabic", "isAutoGenerated": false },
            { "code": "en", "name": "English (auto-generated)", "isAutoGenerated": true },
            { "code": "en", "name": "English - English", "isAutoGenerated": false }
        ],
        "transcriptText": "This program is brought to you by Stanford University. Please visit us at stanford.edu Thank You. I am honored to be with you today at your ...",
        "segments": [
            { "start": 7.47, "duration": 2.899, "text": "This program is brought to you by Stanford University." },
            { "start": 10.47, "duration": 3.973, "text": "Please visit us at stanford.edu" }
        ],
        "srt": null,
        "vtt": null,
        "wordCount": 2301,
        "segmentCount": 244,
        "sourceType": "video",
        "sourceInput": "https://www.youtube.com/watch?v=UF8uR6Z6KLc",
        "position": null,
        "scrapedAt": "2026-10-18T03:48:22.753Z"
    },
    {
        "videoId": "VyICtBxmkWo",
        "title": "【今朝の最新ニュース6本】通勤・通学中にいち早くきょうの最新ニュースをお届け！ NNN NEWS ZIP！(2026年10月15日)",
        "channelName": "日テレNEWS",
        "publishedAt": "2026-10-14",
        "durationSeconds": 470,
        "status": "ok",
        "language": "ja",
        "languageName": "Japanese (auto-generated)",
        "isAutoGenerated": true,
        "transcriptText": "[音楽] NNN最新[音楽]ニュースです。 嫌な農林水産大臣はシャトルバスで指示者 を無料で送迎した問題などを巡り、国会 ...",
        "segments": [
            { "start": 1.964, "duration": 2.02, "text": "[音楽]" },
            { "start": 7, "duration": 6.92, "text": "NNN最新[音楽]ニュースです。" }
        ],
        "wordCount": 1215,
        "segmentCount": 124
    },
    {
        "videoId": "D-WSODwniOc",
        "title": "BOLO SIMPLES DE TRIGO - SUPER FOFINHO",
        "channelName": "Juarez Receitas Caseiras",
        "publishedAt": "2024-11-14",
        "durationSeconds": 196,
        "status": "no_captions",
        "statusMessage": "The video has no captions.",
        "language": null,
        "availableLanguages": [],
        "transcriptText": null,
        "segments": null,
        "wordCount": null
    }
]
```

With **Output format** set to SRT, the `srt` field holds a file you can save as it is:

```
1
00:00:07,470 --> 00:00:10,369
This program is brought to you by Stanford University.

2
00:00:10,470 --> 00:00:14,443
Please visit us at stanford.edu
```

A `SUMMARY` record in the run's key-value store counts transcripts, videos without captions and failures, and names any input that could not be read.

### Tips

- Leave **Preferred languages** empty to get every video in the language it was spoken in.
- For AI tools, pick **Plain text only** to keep rows small, or **Text and timed segments** when you need to link answers back to a moment in the video.
- Automatic captions follow the speech closely but can mishear names and rare words. Creator-made captions read better when they exist.
- Rows with status `failed` are free; run those videos again.
- Live streams get captions only after they end; premieres and upcoming streams are marked `unavailable` until then. So are videos YouTube blocks in the country the request comes from, with YouTube's reason in `statusMessage`.
- To read a channel's Shorts or past live streams, pick those **Channel tabs**, or paste a link such as youtube.com/@name/shorts.

### Integrations

- **API**: start runs and read results over the [Apify API](https://docs.apify.com/api/v2); the API tab shows ready code.
- **Python**: `pip install apify-client`, then
  ```python
  from apify_client import ApifyClient
  client = ApifyClient("<YOUR_API_TOKEN>")
  run = client.actor("stratumics/youtube-transcript-scraper").call(run_input={"videoUrls": ["https://www.youtube.com/watch?v=UF8uR6Z6KLc"], "outputFormat": "text"})
  for item in client.dataset(run["defaultDatasetId"]).iterate_items():
      print(item["title"], item["wordCount"])
  ```
- **JavaScript**: `npm install apify-client`, then
  ```javascript
  import { ApifyClient } from 'apify-client';
  const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
  const run = await client.actor('stratumics/youtube-transcript-scraper').call({ channels: ['@stanford'], maxVideos: 20 });
  const { items } = await client.dataset(run.defaultDatasetId).listItems();
  ```
- **Zapier, Make, n8n**: use the Apify app or node to get transcripts and send them to Google Docs, Notion, Airtable or a summarizing step.
- **AI agents**: connect your agent to this scraper through the Apify MCP server (mcp.apify.com), so it can read any YouTube video's transcript when a question needs it.
- **Webhooks and schedules**: get notified when a run finishes, or read a channel's newest videos every day.

### FAQ

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

Our Actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our Actors, when used for ethical purposes by Apify users, are safe. However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

Transcripts are the words of the video's creator and may be protected by copyright, so check how you may reuse them.

#### Which videos have transcripts?

Most videos with speech have automatic captions, and many also have captions written by the creator. Videos without speech, very new uploads and videos whose creator turned captions off have none; those rows are saved with status `no_captions` and are free.

#### Can it translate transcripts?

No. YouTube refuses automated requests for its machine translation of captions, so the scraper does not offer it. Ask for a language the video already has (`availableLanguages` lists them), or translate `transcriptText` with your own tool.

#### Why can an automatic transcript differ a little from the one on youtube.com?

YouTube keeps more than one version of some automatic captions and does not show the same one to every app and country. In our checks against the transcript panel on youtube.com, 8 of 10 videos matched word for word and timestamp for timestamp (two of them once the same caption track was picked); the other 2 differed in punctuation, spelling marks and line breaks, with 95% of their timestamps within a second.

#### Does it transcribe videos that have no captions?

No. It reads the captions YouTube has; it does not convert audio to text.

#### Why did I get a different language than I asked for?

When a video has none of your languages, you get its original-language transcript, with `isRequestedLanguage` set to false and a note in `statusMessage`.

#### Do I need a proxy?

No. The scraper sends the caption requests through Apify datacenter proxy on its own. You can pick your own proxy in the input to send every request through it.

#### Where can I report a problem?

Open an issue on the Issues tab with your run link and we will look at it.

# Actor input Schema

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

Videos to get transcripts for, one per line: watch, youtu.be, Shorts, live and embed links all work, and so do bare 11-character video ids.

## `channels` (type: `array`):

Channel links or handles, one per line (@mkbhd, a youtube.com/@name, /channel/UC..., /c/ or /user/ link). The newest videos of each channel get transcripts, up to the maximum below. A link to one tab, such as youtube.com/@name/shorts, reads only that tab.

## `playlistUrls` (type: `array`):

Playlist links (youtube.com/playlist?list=...), links to a video played from a playlist (watch?v=...\&list=...), or bare playlist ids. Videos are read in the playlist's own order, up to the maximum below.

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

How many videos to read from each channel tab and each playlist, newest first for channels. Video links are not limited by this.

## `channelTabs` (type: `array`):

Which tabs of each channel to read: long videos, Shorts, or past live streams. Each tab gets up to the maximum above.

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

Transcript languages in order of preference, as codes such as en, es, pt-BR or ja. The first one a video has is used; "en" also matches en-GB and en-US. Leave empty to get each video in its original spoken language. When a video has none of your languages, its original-language transcript is returned and the row says so.

## `preferManualCaptions` (type: `boolean`):

When a language has both creator-made captions and YouTube's automatic ones, use the creator's. Turn off to prefer the automatic ones, which follow the speech word by word.

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

What each row carries: the plain transcript text, timed segments (start, duration, text), both, or a ready subtitle file (SRT or WebVTT, with the plain text as well).

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

How many videos are worked on at the same time. The default is fast and stays within YouTube's limits.

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

YouTube shows captions to Apify's servers only through a proxy, so the scraper sends those requests through Apify datacenter proxy by itself (part of every Apify plan); everything else goes out directly. Pick a proxy here only to send every request through your own.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=UF8uR6Z6KLc"
  ],
  "channels": [],
  "playlistUrls": [],
  "maxVideos": 50,
  "channelTabs": [
    "videos"
  ],
  "languages": [],
  "preferManualCaptions": true,
  "outputFormat": "both",
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Dataset with one row per video.

## `summary` (type: `string`):

Per-input counts, errors and notes for the run (key-value store record SUMMARY).

# 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=UF8uR6Z6KLc"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("stratumics/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=UF8uR6Z6KLc"] }

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

```

## MCP server setup

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