# YouTube Transcript Scraper - Subtitles & Captions API (`delicious_zebu/youtube-transcript-scraper`) Actor

Get transcripts of YouTube videos, Shorts, whole channels, playlists or search results: full text, timestamped segments and SRT or VTT files, in the video's language or every language it has. Creator subtitles first, auto-generated as backup. No API key.

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

## Pricing

from $2.00 / 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

### What does YouTube Transcript Scraper do?

**YouTube Transcript Scraper** gets the transcripts of [YouTube](https://www.youtube.com) videos and Shorts, **one by one or a whole channel, playlist or search at a time**: the full text, timestamped segments like YouTube's *Show transcript* panel, and SRT or WebVTT subtitle files, in the video's own language or in **every language the video has**. It works as an unofficial **YouTube transcript API**: no API key, no quota and no login.

Paste video links, channels or playlists, or type search terms, pick a subtitle language, and download the results as JSON, CSV or Excel, or get them through the API. Subtitles from the creator are used first, and YouTube's auto-generated captions fill in when there are none.

### Why use YouTube Transcript Scraper?

- 📺 **Whole channels, playlists and searches**: add a channel to get its newest videos, Shorts or live replays, a playlist for every video in it, or a search term for the top results. You choose how many videos to take from each.
- 🌍 **Every language in one run**: pick one language, or choose **All languages** to get every subtitle track a video has, including the captions of YouTube's AI-dubbed audio tracks.
- 🎯 **The right language**: the same list as **Subtitles/CC** in the YouTube player. Subtitles written by the creator come before auto-generated captions, and each result says which one you got.
- ⏱️ **Timestamps your way**: plain text for AI and search, timestamped segments with start and end times in seconds, and optional **SRT / WebVTT** files.
- 📊 **One line per row**: the **Segments** view lists every timestamped line as its own row, so the CSV or Excel export is ready to use.
- 🧾 **Clear skips, no charge**: videos without the language you asked for, without captions, or that need a sign-in are skipped, not charged, and listed with the reason.
- 🎬 **Videos, Shorts and live replays**: paste any video link, or just the video ID. Exact view count, duration, publish time and channel come with every transcript.
- ⚡ **Fast**: 20 videos at a time. In our tests, 60 videos took about 10 seconds.

**Popular use cases:** feeding transcripts to ChatGPT, Claude or other AI tools, RAG and search indexes, video summaries and show notes, content research and SEO, translation and subtitling work, accessibility, and building datasets.

| | YouTube Transcript Scraper | YouTube Data API | Copying by hand |
|---|---|---|---|
| Transcripts of any public video | Yes | Only your own videos (OAuth) | Yes, slowly |
| API key / Google Cloud project | Not needed | Required | Not needed |
| All languages in one go | Yes | One request per track | One at a time |
| Timestamps and SRT / VTT | Yes | Yes | Timestamps only |
| Export to CSV / Excel / JSON | Yes | Needs code | Manual |

### What data can you extract?

Each result is one video in one subtitle language.

| Field | Description | Example |
|---|---|---|
| `transcript` | The whole transcript as plain text | `This is a 3. It's sloppily written and rendered...` |
| `segments` | Timestamped lines: `start` and `end` in seconds, `start_time` as shown on YouTube, `text` | `{"start": 4.22, "end": 5.4, "start_time": "0:04", "text": "This is a 3."}` |
| `language` | Subtitle name as shown in the Subtitles/CC menu | `English`, `English (auto-generated)` |
| `language_code` | Language code | `en` |
| `is_auto_generated` | `true` for captions YouTube made from the speech, `false` for subtitles from the creator | `false` |
| `available_languages` | Every subtitle track the video has | `[{"language_code": "ar", "language": "Arabic", ...}]` |
| `subtitles` | The whole SRT or WebVTT file as text, when **Subtitle file** is set | `1\n00:00:04,220 --> 00:00:05,400\nThis is a 3.` |
| `title` | Video title | `But what is a neural network? \| Deep learning chapter 1` |
| `channel_name`, `channel_id`, `channel_url` | Channel name, ID and link | `3Blue1Brown` |
| `published_at` | Exact publish time (UTC) | `2017-10-05T15:11:25Z` |
| `video_duration`, `duration_seconds` | Video length | `18:40`, `1120` |
| `view_count` | Exact view count | `24649096` |
| `video_url`, `video_id` | Video link from your input and video ID | `aircAruvnKk` |
| `description`, `thumbnail_url` | Video description and thumbnail | |
| `source`, `source_position` | The link or search term the video came from, and its position there (newest first for channels) | `@3blue1brown`, `1` |

### How to scrape YouTube transcripts

1. Click **Try for free** on this page and sign in to Apify (a free account is enough).
2. Fill in one or more options: **Videos** (video or Shorts links), **Channels** (for example `@3blue1brown`), **Playlists** (playlist links) or **Search YouTube** (search terms).
3. For channels, playlists and searches, set how many videos to take from each. Then pick a **Subtitle language**: **Original language**, **All languages**, or a specific language.
4. Click **Start**. The log shows each video as it's done.
5. Download the transcripts as JSON, CSV, Excel or HTML, or get them through the API. Use the **Segments** view for one timestamped line per row.

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

You only pay for the transcripts you get: one video in one language is one result. With **All languages**, each language counts as a result. Listing the videos of a channel, playlist or search is free, and videos that are skipped (no captions, no subtitles in your language, age-restricted, members-only or unavailable) are not charged. See the [Pricing](https://apify.com/delicious_zebu/youtube-transcript-scraper/pricing) tab for the current price.

To keep a run within budget, set a **Max cost per run** in the run options. The Actor stops as soon as the limit is reached.

New to Apify? The free plan includes monthly platform credit, so you can try this Actor at no cost.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| **Option 1 — Videos** | | | One transcript per video. |
| YouTube video links (`urls`) | List | — | Video, Shorts or live links, or video IDs, one per line. Example: `https://youtu.be/aircAruvnKk` |
| **Option 2 — Channels** | | | The newest videos of each channel. |
| Channels (`channels`) | List | — | Channel handle, channel link or channel ID, one per line. Example: `@3blue1brown` |
| Channel tab (`channel_tab`) | Select | `videos` | `videos`, `shorts` or `streams` (Live), like the tabs on the channel page. A channel link ending in `/shorts` or `/streams` uses that tab. |
| Max videos per channel (`max_videos_per_channel`) | Number | `20` | How many of the newest videos to take from each channel. `0` takes all. |
| **Option 3 — Playlists** | | | The videos of each playlist, in playlist order. |
| Playlists (`playlists`) | List | — | Playlist links or IDs, one per line. Example: `https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi` |
| Max videos per playlist (`max_videos_per_playlist`) | Number | `20` | How many videos to take from each playlist, from the top. `0` takes the whole playlist. |
| **Option 4 — Search YouTube** | | | The top videos for a search. |
| Search terms or search result links (`search_keywords`) | List | — | Search terms (videos only, like YouTube's **Type: Video** filter), or YouTube search results page links to keep your filters. Example: `neural networks explained` |
| Max videos per search (`max_videos_per_search`) | Number | `20` | How many of the top videos to take from each search. |
| **Transcript options** | | | These apply to all four options. |
| Subtitle language (`language`) | Select | `original` | `original` (the language spoken in the video, the one *Show transcript* opens), `all` (every subtitle track), or a language code such as `es`, `pt`, `ja` or `zh-Hans`. Same list as **Settings → Subtitles/CC** in the YouTube player. |
| Include auto-generated captions (`include_auto_generated`) | Checkbox | `true` | Use YouTube's auto-generated captions when there are no subtitles from the creator. Turn off for creator subtitles only. |
| Subtitle file (`subtitle_format`) | Select | `none` | `srt` or `vtt` adds the whole subtitle file as text in `subtitles`. |

**Transcripts of a few videos in their own language**

```json
{
    "urls": [
        "https://www.youtube.com/watch?v=aircAruvnKk",
        "https://www.youtube.com/shorts/CEJXqm2eiJ0"
    ]
}
```

**Spanish subtitles, from the creator only, as SRT files**

```json
{
    "urls": ["https://www.youtube.com/watch?v=aircAruvnKk"],
    "language": "es",
    "include_auto_generated": false,
    "subtitle_format": "srt"
}
```

**The 20 newest videos of a channel**

```json
{
    "channels": ["@3blue1brown"],
    "max_videos_per_channel": 20
}
```

**The 10 newest Shorts of a channel**

```json
{
    "channels": ["@LinusTechTips"],
    "channel_tab": "shorts",
    "max_videos_per_channel": 10
}
```

**A whole playlist, plus the top 10 videos for a search**

```json
{
    "playlists": ["https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi"],
    "max_videos_per_playlist": 0,
    "search_keywords": ["neural networks explained"],
    "max_videos_per_search": 10
}
```

**Every subtitle language of a video**

```json
{
    "urls": ["https://www.youtube.com/watch?v=y1hZ3EalPQU"],
    "language": "all"
}
```

### Output

Each transcript is one item in the dataset, in the order of your input: videos first, then channels, playlists and searches. Here is a real result (text, segments and lists shortened):

```json
{
    "video_url": "https://www.youtube.com/watch?v=aircAruvnKk",
    "video_id": "aircAruvnKk",
    "title": "But what is a neural network? | Deep learning chapter 1",
    "channel_name": "3Blue1Brown",
    "channel_id": "UCYO_jab_esuFRV4b17AJtAw",
    "channel_url": "https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw",
    "published_at": "2017-10-05T15:11:25Z",
    "video_duration": "18:40",
    "duration_seconds": 1120,
    "view_count": 24649096,
    "language": "English",
    "language_code": "en",
    "is_auto_generated": false,
    "transcript": "This is a 3. It's sloppily written and rendered at an extremely low resolution of 28x28 pixels, but your brain has no trouble recognizing it as a 3. And I want ...",
    "segments": [
        {"start": 4.22, "end": 5.4, "start_time": "0:04", "text": "This is a 3."},
        {"start": 6.06, "end": 10.713, "start_time": "0:06", "text": "It's sloppily written and rendered at an extremely low resolution of 28x28 pixels,"}
    ],
    "available_languages": [
        {"language_code": "ar", "language": "Arabic", "is_auto_generated": false},
        {"language_code": "en", "language": "English", "is_auto_generated": false},
        {"language_code": "en", "language": "English (auto-generated)", "is_auto_generated": true}
    ],                                    // 31 tracks for this video
    "subtitles": null,                    // SRT or WebVTT text when "Subtitle file" is set
    "description": "What are the neurons, why are there layers, and what is the math underlying it? ...",
    "thumbnail_url": "https://i.ytimg.com/vi_webp/aircAruvnKk/sddefault.webp",
    "source": "https://www.youtube.com/watch?v=aircAruvnKk",
    "source_position": null              // Position in the channel, playlist or search the video came from
}
```

The **Segments** view in the Output tab shows one timestamped line per row (title, language, time, start, end, text), which is the easiest way to work with transcripts in a spreadsheet.

### Tips and limitations

- **Original language** is the language spoken in the video. If the creator uploaded subtitles in that language you get those, otherwise YouTube's auto-generated captions.
- **Language matching**: a language also matches its regional versions, so Portuguese finds Portuguese (Brazil) and Spanish finds Spanish (Latin America). Chinese (Simplified) and Chinese (Traditional) are kept apart.
- **AI-dubbed videos**: when YouTube has dubbed a video into other languages, each dubbed language has its own auto-generated captions, and you can pick them like any other language.
- **Auto-translate is not available.** YouTube blocks automatic translations for tools like this one, so you get the languages the video really has. `available_languages` shows them.
- **Skipped videos**: videos with no captions, live streams that are still on air, age-restricted, members-only and private videos are skipped and not charged. The reasons are in **SKIPPED_VIDEOS** in the Storage tab.
- **Long videos are fine**: a 4.5-hour course comes back as one result with almost 3,000 segments.
- **Channels**: you get the newest videos of the tab you pick in **Channel tab** (Videos, Shorts or Live). A channel link ending in `/shorts` or `/streams` uses that tab instead. Members-only videos are not included, because their captions need a sign-in.
- **Playlists**: use the playlist link (`youtube.com/playlist?list=...`). A video link that also has `&list=` gets just that video. Mix playlists (auto-generated radio) can't be listed.
- **Search filters**: search on YouTube, set filters such as upload date or duration, and paste the results page link. Your filters are kept.
- **Max videos counts videos, not transcripts**: videos without subtitles are skipped and not charged, so you can get fewer transcripts than the number you set. The same video found in several places is processed once.
- **Pasted a link in the wrong box?** It still works: links are recognised by what they point to, so a channel link in the Videos box is treated as a channel.

### FAQ

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

This Actor only collects data that YouTube shows publicly. 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.

#### Do I need a YouTube API key or account?

No. Add your videos, channels, playlists or search terms and start the run.

#### Can I get the transcripts of a whole YouTube channel?

Yes. Add the channel in **Channels** (for example `@3blue1brown`) and set **Max videos per channel** to the number of newest videos you want, or `0` for all of them. Pick **Shorts** or **Live** in **Channel tab** for Shorts or past live streams.

#### Can it translate transcripts?

No. YouTube's auto-translate can't be downloaded by tools like this one, so the Actor returns the subtitles the video really has. Many popular videos have subtitles from the creator in several languages, and AI-dubbed videos have captions for each dubbed language. You can also send the transcript to an AI tool for translation.

#### Why was a video skipped?

Because it has no captions, doesn't have the language you picked, is age-restricted, members-only or private, or no longer exists. Channels that don't exist, Mix playlists and searches with no results are skipped too. Skipped videos are not charged. The run's status message counts them by reason, and **SKIPPED_VIDEOS** in the Storage tab lists each one with the languages it does have.

#### How is "All languages" charged?

Each language is one result. A video with subtitles in 20 languages gives 20 results.

#### Can I get one timestamped line per row?

Yes. Open the **Segments** view in the Output tab, or export the dataset with that view, and every line of every transcript becomes its own row.

#### Does it work with YouTube Shorts?

Yes. Paste the Shorts link (or its video ID) like any other video.

#### Can I use it through the API, with n8n or with AI agents?

Yes. You can run it with the [Apify API](https://docs.apify.com/api/v2), the Python and JavaScript clients, integrations such as Make, Zapier and n8n, or the [Apify MCP server](https://mcp.apify.com) so AI agents can fetch transcripts themselves.

### Related Actors

| Actor | What it does |
|---|---|
| [YouTube Channel Scraper - All Videos, Views & Dates](https://apify.com/delicious_zebu/youtube-channel-video-scraper) | Every video, Short and live stream of a channel |
| [YouTube Search Scraper - Videos & Shorts by Keyword](https://apify.com/delicious_zebu/youtube-video-scraper-by-keyword) | Videos that match a search term |
| [YouTube Video Details Scraper - Views, Likes & Channel Stats](https://apify.com/delicious_zebu/youtube-video-data-scraper) | Full details of any list of video links |
| [YouTube Comments Scraper - Replies, Likes & Shorts](https://apify.com/delicious_zebu/youtube-comments-replies-scraper) | Comments and replies of any video |

### Support

Found a problem or need another field? Open an issue in the **Issues** tab and we'll get back to you.

# Actor input Schema

## `urls` (type: `array`):

Video, Shorts or live links, or the 11-character video ID, one per line. Example: https://youtu.be/aircAruvnKk or just aircAruvnKk. Each video is processed only once.

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

Channel handle, channel link or channel ID (starts with UC), one per line. Example: @3blue1brown, https://www.youtube.com/@LinusTechTips or UCYO_jab_esuFRV4b17AJtAw.

## `channel_tab` (type: `string`):

Which tab of the channel page to take videos from: <b>Videos</b>, <b>Shorts</b> or <b>Live</b> (past live streams), like the tabs under the channel name on YouTube. Members-only videos are not included. A channel link that ends in /shorts or /streams uses that tab.

## `max_videos_per_channel` (type: `integer`):

How many of the newest videos to take from each channel. Use 0 for all of them.

## `playlists` (type: `array`):

Playlist links (or playlist IDs), one per line. Example: https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi. Mix playlists (YouTube's auto-generated radio) can't be listed.

## `max_videos_per_playlist` (type: `integer`):

How many videos to take from each playlist, from the top. Use 0 for the whole playlist.

## `search_keywords` (type: `array`):

One per line. A search term finds videos only (YouTube's <b>Type: Video</b> filter), in YouTube's order. To use filters such as upload date or duration, search on YouTube, set the filters and paste the results page link. Example: neural networks explained, or https://www.youtube.com/results?search_query=bread+recipe\&sp=EgIIAw%253D%253D (uploaded this week).

## `max_videos_per_search` (type: `integer`):

How many of the top videos to take from each search. Use 0 to take every result YouTube shows.

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

The same languages as <b>Settings → Subtitles/CC</b> in the YouTube player. <b>Original language</b> is the language spoken in the video, the one <i>Show transcript</i> opens. <b>All languages</b> returns every subtitle track the video has, one result per language. Subtitles from the creator are used before auto-generated captions. A video that doesn't have the language you pick is skipped and not charged. YouTube's auto-translate is not available.

## `include_auto_generated` (type: `boolean`):

Captions YouTube makes from the speech, shown as "(auto-generated)" in the Subtitles/CC menu. Subtitles from the creator are always used first. Turn this off to get only subtitles uploaded by the creator.

## `subtitle_format` (type: `string`):

Also put the whole subtitle file, as text, in the <code>subtitles</code> field, ready to save as an .srt or .vtt file.

## Actor input object example

```json
{
  "urls": [
    "https://www.youtube.com/watch?v=aircAruvnKk"
  ],
  "channels": [
    "@3blue1brown"
  ],
  "channel_tab": "videos",
  "max_videos_per_channel": 20,
  "playlists": [
    "https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi"
  ],
  "max_videos_per_playlist": 20,
  "search_keywords": [
    "neural networks explained"
  ],
  "max_videos_per_search": 20,
  "language": "original",
  "include_auto_generated": true,
  "subtitle_format": "none"
}
```

# Actor output Schema

## `overview` (type: `string`):

Table view of transcripts using the 'overview' view from dataset_schema.json.

## `segments` (type: `string`):

One row per timestamped line using the 'segments' view from dataset_schema.json.

## `rawResults` (type: `string`):

All transcript items from the default dataset without a specific view.

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

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

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

```

## MCP server setup

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