# YouTube Transcript Scraper - Subtitles, Captions & SRT (`socialscrapers/youtube-transcript-scraper`) Actor

YouTube Transcript Scraper and API: download transcripts, subtitles and closed captions (CC) of YouTube videos, Shorts, past live streams and channels in bulk, in any language, manual or auto-generated, with timestamps, full text and SRT/VTT files. No login, no API key. $0.60 per 1,000 transcripts.

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

## Pricing

from $0.48 / 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** downloads the **transcript, subtitles and closed captions (CC)** of any public YouTube video, Short or past live stream, in bulk, from video URLs or whole channels. You get the timed lines, the full text in one piece, its word count and language, optional **SRT and WebVTT subtitle files**, and the video's title, channel, publish date, duration and views. Human-made and auto-generated captions, in every language a video has. **No login, no API key**, from **$0.60 per 1,000 transcripts**.

### What does YouTube Transcript Scraper do?

YouTube Transcript Scraper turns YouTube captions into clean text and data:

- 📝 **Transcripts in any language.** Human-made captions and YouTube's auto-generated ones. List the languages you want in order of preference and each video returns the first one it has, or switch on **Return every language** to get every caption track.
- ⏱️ **Timestamps and full text.** Each transcript comes as timed segments (start, duration, text) and as one clean full text with its word count: ready for a language model, a search index or a spreadsheet.
- 🎬 **SRT and WebVTT files.** Add each transcript as a ready-to-use `.srt` or `.vtt` subtitle file for video editors, players and translation tools.
- 📺 **Whole channels.** Paste a channel URL or @handle to get the transcripts of its latest videos, Shorts (`/shorts`) or past live streams (`/streams`), with no upper limit.
- 🔗 **Any link works:** watch URLs, youtu.be short links, Shorts, live and embed URLs, mobile and music links, or bare 11-character video IDs.
- ℹ️ **Video details in the same result:** title, channel name, ID and URL, publish date, duration, views, category, keywords, description, thumbnail, and every caption language the video has.
- ✅ **No surprises:** a video without a usable transcript still gets a result saying why (no captions, private, age-restricted, members-only, live now), and you are not charged for it.

### What data can you extract from YouTube transcripts?

| Data | Fields |
| --- | --- |
| **Transcript** | `fullText`, `wordCount`, `language`, `languageName`, `isAutoGenerated` |
| **Timed segments** | `segments`: `start` and `duration` in seconds, `text` |
| **Subtitle files** (optional) | `srt`, `vtt` |
| **Video** | `videoId`, `url`, `title`, `description`, `publishedAt`, `durationSeconds`, `viewCount`, `category`, `keywords`, `thumbnailUrl` |
| **Channel** | `channelName`, `channelId`, `channelUrl` |
| **Languages** | `availableLanguages`: every caption track the video has |
| **No transcript** | `error` and `errorMessage` (free) |

### How to get the transcript of a YouTube video

1. Open YouTube Transcript Scraper on Apify and click **Try for free**.
2. Paste **video URLs** (or IDs), **channel URLs**, or both.
3. Choose your **languages** (for example `en`, `es`), or switch on **Return every language**.
4. Keep **Include timestamps** on for timed segments, and pick **Subtitle files** (SRT, WebVTT) if you need them.
5. Click **Start**, then download the transcripts as JSON, CSV, Excel, XML or HTML, or read them through the API.

#### How to download YouTube subtitles as SRT

Add the videos, choose the language, and under **Subtitle files** pick **SRT** (or **WebVTT**). Each result then carries the subtitles as a complete `.srt` file in the `srt` field, ready to save or load into an editor.

#### How to get transcripts of a whole YouTube channel

Paste the channel URL, for example `https://www.youtube.com/@NASA`, and set **Max videos per channel**. Its latest videos come first. Use `https://www.youtube.com/@NASA/shorts` for its Shorts or `/streams` for its past live streams.

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

Pay per transcript, with platform usage and proxies included and no monthly fee for the Actor:

| Result | Price per 1,000 | Silver plan | Gold plan |
| --- | --- | --- | --- |
| Transcripts | **$0.60** | $0.54 | $0.48 |
| Videos without a transcript | **free** | free | free |

A transcript is one video in one language, so a video costs one transcript unless you ask for every language. SRT and WebVTT files are included at no extra cost.

Examples:

- **1,000 videos** in English: **$0.60**.
- **A channel's last 500 videos** with SRT files: **$0.30**.

Apify's free plan comes with $5 of platform credit every month, enough for about 8,000 transcripts. Set a **maximum cost per run** when you start the Actor and it stops cleanly before the first transcript that would go over it.

### Input example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=iG9CE55wbtY",
    "https://youtu.be/aBcDeFgHiJk",
    "https://www.youtube.com/shorts/aBcDeFgHiJk"
  ],
  "channelUrls": ["https://www.youtube.com/@NASA"],
  "maxVideosPerChannel": 50,
  "languages": ["en", "es"],
  "allLanguages": false,
  "includeTimestamps": true,
  "subtitleFormats": ["srt"],
  "includeAutoGenerated": true
}
```

How the language is picked, for each video:

1. The first language in your list that the video has, human-made captions before auto-generated ones. `en` also matches regional variants such as `en-US`, and `pt-BR` falls back to `pt`.
2. If the video has none of your languages: its best available transcript, usually the one in its original language.

### Output example

One result per video and transcript language. The **Overview** view shows one row per transcript, and the **Timed segments** view one row per line.

```json
{
  "videoId": "aBcDeFgHiJk",
  "url": "https://www.youtube.com/watch?v=aBcDeFgHiJk",
  "title": "How Transcripts Work",
  "channelName": "Example Channel",
  "channelId": "UCxxxxxxxxxxxxxxxxxxxxxx",
  "channelUrl": "https://www.youtube.com/@examplechannel",
  "publishedAt": "2024-03-14T16:00:07.000Z",
  "durationSeconds": 642,
  "viewCount": 1520311,
  "category": "Education",
  "language": "en",
  "languageName": "English",
  "isAutoGenerated": false,
  "wordCount": 1873,
  "availableLanguages": [
    { "language": "en", "languageName": "English", "isAutoGenerated": false },
    { "language": "en", "languageName": "English", "isAutoGenerated": true },
    { "language": "es", "languageName": "Spanish", "isAutoGenerated": false }
  ],
  "thumbnailUrl": "https://i.ytimg.com/vi/aBcDeFgHiJk/maxresdefault.jpg",
  "keywords": ["captions", "subtitles"],
  "description": "The video's description...",
  "fullText": "Hello and welcome. Today we look at how captions are timed...",
  "srt": "1\n00:00:00,480 --> 00:00:03,120\nHello and welcome.\n\n2\n00:00:03,120 --> 00:00:07,320\nToday we look at how captions are timed...\n",
  "segments": [
    { "start": 0.48, "duration": 2.64, "text": "Hello and welcome." },
    { "start": 3.12, "duration": 4.2, "text": "Today we look at how captions are timed..." }
  ],
  "sourceUrl": "https://youtu.be/aBcDeFgHiJk",
  "scrapedAt": "2026-11-08T10:00:00.000Z"
}
```

- `start` and `duration` are in seconds. Auto-generated captions keep each line on screen while the next one is spoken; their segments end where the next one starts, so segments never overlap.
- `fullText` is the transcript as one string, with line breaks and formatting tags removed. `wordCount` counts words the way the language writes them, so Chinese and Japanese are counted too.
- `srt` and `vtt` appear when you pick them under **Subtitle files**; `segments` is left out when **Include timestamps** is off.

A video without a usable transcript gets one free result with the reason in `error`:

```json
{
  "videoId": "aBcDeFgHiJk",
  "url": "https://www.youtube.com/watch?v=aBcDeFgHiJk",
  "title": "A Silent Video",
  "availableLanguages": [],
  "error": "no transcript",
  "errorMessage": "The video has no captions."
}
```

`error` is one of `no transcript`, `video unavailable` (private, removed or blocked in the proxy's country), `age restricted`, `members only`, `live stream` (live now or not started; captions come after it ends) and `fetch failed` (try the video again later). A `SUMMARY` record in the run's key-value store lists how many transcripts were saved, the videos without one and why, and any input that could not be read.

### Use cases

- **AI and LLM datasets:** clean spoken-language text from a topic, a channel or a list of videos, with timestamps for alignment.
- **Retrieval and chatbots (RAG):** index what videos say and link answers back to the second they were said.
- **Content research:** read what creators in your niche talk about and find quotes without watching hours of video.
- **SEO and repurposing:** turn videos into articles, show notes, summaries and keyword lists.
- **Subtitles, translation and accessibility:** SRT and WebVTT files with their timings, in every language the video has.

### Use it via API, Python, JavaScript and integrations

Run it and get the transcripts in one call with the [Apify API](https://docs.apify.com/api/v2):

```bash
curl -X POST "https://api.apify.com/v2/acts/socialscrapers~youtube-transcript-scraper/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"videoUrls": ["https://www.youtube.com/watch?v=iG9CE55wbtY"], "languages": ["en"]}'
```

Python, with the [Apify client](https://docs.apify.com/api/client/python):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("socialscrapers/youtube-transcript-scraper").call(run_input={
    "channelUrls": ["https://www.youtube.com/@NASA"],
    "maxVideosPerChannel": 20,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item.get("wordCount"))
```

JavaScript, with the [Apify client](https://docs.apify.com/api/client/js):

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('socialscrapers/youtube-transcript-scraper').call({ videoUrls: ['https://youtu.be/iG9CE55wbtY'], subtitleFormats: ['srt'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

You can also **schedule** runs, get a **webhook** when a run finishes, and send the results to **Make, Zapier, n8n, Google Sheets, Slack** and other tools through [Apify integrations](https://docs.apify.com/integrations). AI agents and assistants can run it through [Apify's MCP server](https://docs.apify.com/mcp).

### YouTube Data API vs YouTube Transcript Scraper

| | Official YouTube Data API | YouTube Transcript Scraper |
| --- | --- | --- |
| Setup | Google Cloud project, API key and sign-in | None: paste video or channel URLs |
| Whose captions | Only videos you are allowed to edit | Any public video |
| Output | Caption file only | Full text, timed segments, SRT, WebVTT and video details |

### Limits

- **Public videos only.** Private, members-only and age-restricted videos need a signed-in account, so they are reported with the reason and not charged.
- **Only the captions a video has.** YouTube makes auto-generated captions for most videos with speech, but not for music-only videos, and not right away for brand-new uploads. There is no machine translation: a language the video has no captions in falls back to the best available one.
- **Live streams** have captions only after they end.
- **Videos blocked in some countries** are reported as `video unavailable` when they cannot be read from the proxy's location. Set a proxy country to read them from a country where they are available.
- Keep the default residential proxy for large runs.
- **Datacenter proxy choices fall back to residential.** If you pick Apify Proxy without the RESIDENTIAL group, the first session YouTube refuses moves the run to RESIDENTIAL, in the same country; custom proxy URLs are used exactly as given.
- **Share links work as they are**: `youtu.be/…` links, links with the app's `?si=…` share parameter, and `/shorts/…`, `/live/…` and `/embed/…` links all name their video.
- **A run with 0 transcripts still succeeds when your input was fine.** When a video has no captions, is private or deleted, or a channel does not exist, the run ends as Succeeded with a status message naming each input and why, and nothing is charged. A run fails only when no input is usable at all, or when YouTube refuses every one of 3 or more inputs.

### FAQ

**Is it legal to scrape YouTube transcripts?**
YouTube Transcript Scraper collects only captions that anyone can see on YouTube without signing in. You are responsible for how you use them, including copyright, YouTube's terms and the laws that apply to you.

**Do I need a YouTube account, cookies or an API key?**
No. Paste video or channel URLs and start the run.

**What happens when a video has no transcript?**
You get one free result for it, with the reason in `error` and the video's details, so you know what happened to every video you asked for.

**How do I get only human-made captions?**
Turn off **Include auto-generated captions**. Videos with only auto-generated captions are then reported as `no transcript`.

**How do I get every language of a video?**
Turn on **Return every language**. Each language is a separate result, charged as one transcript.

**Can I download YouTube subtitles as an SRT file?**
Yes. Pick **SRT** (or **WebVTT**) under **Subtitle files**; each result then holds the complete file.

**How fast is it?**
About 100 videos in half a minute in our tests.

### Other scrapers by Social Scrapers

| Scraper | What it gets |
| --- | --- |
| [YouTube Scraper](https://apify.com/socialscrapers/youtube-scraper) | YouTube videos, Shorts, channels, playlists, hashtags, comments and subtitles |
| [Instagram Profile Scraper](https://apify.com/socialscrapers/instagram-profile-scraper) | Instagram profiles with their latest posts |
| [Instagram Post Scraper](https://apify.com/socialscrapers/instagram-post-scraper) | Instagram posts and reels with comments |
| [Facebook Groups Scraper](https://apify.com/socialscrapers/facebook-groups-scraper) | Posts from public Facebook groups |
| [Facebook Profile Scraper](https://apify.com/socialscrapers/facebook-profile-scraper) | Public Facebook profile and Page details |
| [Facebook Profile Posts Scraper](https://apify.com/socialscrapers/facebook-profile-posts-scraper) | Posts from Facebook profiles and Pages |
| [Facebook Ads Library Scraper](https://apify.com/socialscrapers/facebook-ads-library-scraper) | Ads from Meta's Ad Library |
| [X (Twitter) Profile Scraper](https://apify.com/socialscrapers/x-profile-scraper) | X (Twitter) profiles |
| [Threads Scraper](https://apify.com/socialscrapers/threads-scraper) | Threads profiles, posts and replies |
| [Reddit Scraper](https://apify.com/socialscrapers/reddit-scraper) | Reddit posts, comments, users and search |
| [Quora Scraper](https://apify.com/socialscrapers/quora-scraper) | Quora questions, answers and profiles |
| [LinkedIn Jobs Scraper](https://apify.com/socialscrapers/linkedin-jobs-scraper) | Job listings from LinkedIn |

# Actor input Schema

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

Videos to get transcripts for, one per line: watch URLs (https://www.youtube.com/watch?v=…), short links (https://youtu.be/…, with or without the app's ?si=… share parameter), Shorts, live and embed URLs, or bare 11-character video IDs.

## `channelUrls` (type: `array`):

Channels to take the latest videos from, newest first: https://www.youtube.com/@handle, /channel/UC…, /c/… or /user/… URLs, or a bare @handle. A URL ending in /shorts or /streams takes that tab instead of Videos.

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

How many of each channel's latest videos to get transcripts for, newest first. No upper limit: a channel gives as many as it has. Example: <code>500</code>.

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

Language codes in order of preference, such as en, es or pt-BR. Each video returns the first of these languages it has (human-made captions before auto-generated ones). A video with none of them returns its best available transcript, usually in its original language. Leave empty to always get the best available one.

## `allLanguages` (type: `boolean`):

Return every caption track of each video (one result per language, human-made and auto-generated), instead of one transcript per video. Preferred languages are then ignored.

## `includeTimestamps` (type: `boolean`):

Add the timed segments (start, duration and text of each line). Turn off to get only the full text.

## `subtitleFormats` (type: `array`):

Also add each transcript as a ready-to-use subtitle file: SRT, WebVTT, or both. Example: <code>SRT</code> for video editors and players.

## `includeAutoGenerated` (type: `boolean`):

Use YouTube's automatic (speech recognition) captions when a video has no human-made ones in your language. Turn off to get human-made captions only.

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

Keep the default residential proxy: YouTube limits how many transcripts one IP address may download.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=iG9CE55wbtY"
  ],
  "maxVideosPerChannel": 20,
  "languages": [
    "en"
  ],
  "allLanguages": false,
  "includeTimestamps": true,
  "includeAutoGenerated": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

No description

# 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=iG9CE55wbtY"
    ],
    "languages": [
        "en"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("socialscrapers/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=iG9CE55wbtY"],
    "languages": ["en"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("socialscrapers/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=iG9CE55wbtY"
  ],
  "languages": [
    "en"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call socialscrapers/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

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