# YouTube Transcript Scraper API - YouTube Subtitles (`autofacts/youtube-subtitle-transcript-scraper`) Actor

Get YouTube transcripts, subtitles and captions from videos, Shorts, playlists and whole channels. Download as SRT, VTT, plain text, JSON with timestamps or clean LLM-ready text, in 100+ languages, with video metadata. Run it in Console or call it as an API. You pay only per transcript extracted.

- **URL**: https://apify.com/autofacts/youtube-subtitle-transcript-scraper.md
- **Developed by:** [Proooxy](https://apify.com/autofacts) (community)
- **Categories:** AI, Developer tools, SEO tools
- **Features:** Limited permissions
- **Stats:** 67 total users, 5 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 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 API - YouTube Subtitles

Get the transcript of any YouTube video as text, or its subtitles and captions in SRT or VTT format — for one video, a list of videos, a whole playlist or an entire channel.

This YouTube transcript extractor reads the captions YouTube has for each video, in 100+ languages, and falls back to auto-generated captions when there are no manual ones. Run it in Apify Console with no code, or call it as a YouTube transcript API from your own code or an AI agent.

### 🎯 What you get

For each video, the scraper returns:

- **Full transcript text** with timestamps
- **Rich video metadata** — title, channel, description, view count, thumbnail, publish date
- **Language info** — detected language, auto-generated flag, all available languages listed
- **Multiple output formats** — pick what fits your workflow

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

1. Paste one or more YouTube URLs or video IDs into **urls**.
2. Pick an **outputFormat**: `text` for plain text, `srt` or `vtt` for subtitles, `json` for timestamped segments, or `llm` for clean text to feed an AI model.
3. Set **languages** in order of preference, for example `["en", "es"]`.
4. Start the run, then export the results as JSON, CSV or Excel, or read them over the API.

The scraper reads the captions YouTube already has. A video with no captions at all, manual or auto-generated, has no transcript to read: it shows up in the results with an `error` field and you are not charged for it.

### 📤 Download YouTube subtitles as SRT, VTT, text or JSON

| Format | Best for |
|--------|----------|
| **JSON** | Apps, databases, APIs — structured data with timestamps per segment |
| **SRT** | Video editors, media players — standard subtitle file format |
| **VTT** | Web players, HTML5 video — WebVTT subtitle format |
| **Text** | Search indexing, content analysis — plain text joined together |
| **LLM** | AI/ML pipelines, RAG, fine-tuning — clean text with annotations stripped |

The **LLM format** automatically removes `[Music]`, `[Applause]`, speaker labels, and other non-speech annotations so you get pure spoken content ready for language models.

With `srt` or `vtt`, each result also carries the complete subtitle file in its `srt` or `vtt` field. Save that text as a `.srt` or `.vtt` file and it loads in video players and editors.

### 🔗 Supported URL types

You can pass any of these as input:

- `https://www.youtube.com/watch?v=dQw4w9WgXcQ` — standard video
- `https://youtu.be/dQw4w9WgXcQ` — short link
- `https://www.youtube.com/shorts/dQw4w9WgXcQ` — YouTube Shorts
- `https://www.youtube.com/playlist?list=PLxxxxx` — full playlist
- `https://www.youtube.com/@channelname` — all videos from a channel
- `dQw4w9WgXcQ` — just the video ID

Mix and match in a single run — the scraper handles them all.

### 💡 Transcripts for a whole playlist or channel

Pass a playlist URL or a channel URL and the scraper lists the videos in it, then returns one transcript per video in the same run. A channel URL covers the videos on the channel's **Videos** tab.

Set **maxVideos** to cap how many videos the run processes in total, which keeps a first test small:

```json
{
    "urls": ["https://www.youtube.com/@TED"],
    "outputFormat": "text",
    "languages": ["en"],
    "maxVideos": 50
}
```

### 📋 Input options

| Option | Default | Description |
|--------|---------|-------------|
| **urls** | — | List of YouTube URLs or video IDs to process |
| **outputFormat** | `json` | Output format: `json`, `srt`, `vtt`, `text`, or `llm` |
| **languages** | `["en"]` | Preferred languages in priority order (e.g. `["en", "ja", "de"]`) |
| **includeAutoGenerated** | `true` | Use YouTube's auto-generated captions when manual ones aren't available |
| **maxVideos** | `0` (unlimited) | Cap on the videos the run processes in total, playlists and channels included |
| **maxConcurrency** | `3` | How many videos to process in parallel (1–10) |
| **proxy** | Apify Proxy | Proxy settings — residential proxies recommended |

You can also use **startUrls** (the `[{url: "..."}]` format) instead of **urls** — both work.

### 📋 Example input

```json
{
    "urls": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        "https://youtu.be/JGwWNGJdvx8"
    ],
    "outputFormat": "llm",
    "languages": ["en"],
    "maxConcurrency": 2
}
```

### 📤 Example output

Each video produces one result in the dataset:

```json
{
    "videoId": "dQw4w9WgXcQ",
    "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "title": "Rick Astley - Never Gonna Give You Up (Official Video)",
    "channelName": "Rick Astley",
    "channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
    "description": "The official video for \"Never Gonna Give You Up\" by Rick Astley...",
    "publishDate": "2009-10-25",
    "viewCount": 1761003712,
    "thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/sddefault.jpg",
    "availableLanguages": ["en", "de-DE", "ja", "pt-BR", "es-419"],
    "language": "en",
    "languageName": "English",
    "isAutoGenerated": false,
    "duration": 213,
    "wordCount": 487,
    "segmentCount": 61,
    "text": "We're no strangers to love, you know the rules and so do I...",
    "segments": [
        { "text": "We're no strangers to love", "start": 18.64, "end": 21.88 },
        { "text": "You know the rules and so do I", "start": 22.64, "end": 26.96 }
    ],
    "extractedAt": "2026-04-10T07:00:00.000Z",
    "error": null
}
```

When using **SRT** or **VTT** format, the result includes an `srt` or `vtt` field with the formatted subtitle file content.

### 🚀 YouTube transcript API for Python and JavaScript

Call the scraper from your own code with the Apify API client and read the records shown above:

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('autofacts/youtube-subtitle-transcript-scraper').call({
    urls: ['https://www.youtube.com/watch?v=dQw4w9WgXcQ'],
    outputFormat: 'text',
    languages: ['en'],
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const video of items) console.log(video.title, video.text);
```

```python
import os
from apify_client import ApifyClient

client = ApifyClient(token=os.environ["APIFY_TOKEN"])
run = client.actor("autofacts/youtube-subtitle-transcript-scraper").call(run_input={
    "urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
    "outputFormat": "text",
    "languages": ["en"],
})
for video in client.dataset(run.default_dataset_id).iterate_items():
    print(video["title"], video["text"])
```

The Python example uses `apify-client` 3.x, where a run is an object (`run.default_dataset_id`). The plain HTTP call is in **Use with AI agents** below.

### 💡 Recommendations

**For best results:**

- Use **residential proxies** (the default) — they work much better with YouTube than datacenter proxies
- Start with **maxConcurrency: 1** if you're processing many videos, then increase gradually
- Set **languages** to your target language — the scraper picks the best available match
- Use the **LLM format** if you're feeding transcripts into AI models — it strips all the noise

**For large jobs:**

- Use playlists or channel URLs to batch-process videos in one run
- Set **maxVideos** to limit playlist/channel scrapes during testing
- The scraper handles failures gracefully — if one video fails, the rest still process. Failed videos show up in the results with an `error` field so you can retry them later

**For AI/ML workflows:**

- The **LLM output format** gives you clean, annotation-free text optimized for context windows
- **JSON format** preserves timestamps, which is useful for building time-aligned datasets
- The `segments` array gives you natural sentence boundaries from the original captions

### 💳 Fair billing

You're never charged for videos that fail to extract. You only pay for successful results.

### 🌍 Language support

The scraper supports all languages that YouTube captions are available in — over 100 languages. Set your preferred languages in priority order and the scraper will pick the best available match.

If manual captions aren't available in your language, YouTube's auto-generated captions are used as a fallback (unless you disable this with `includeAutoGenerated: false`).

### 🛠️ Error handling

The scraper is designed to be resilient:

- If a video has no captions, it reports the error and moves on
- If YouTube rate-limits a request, the scraper retries with backoff
- If one extraction method fails, it automatically tries alternatives
- Failed videos appear in the dataset with a descriptive `error` field — successful videos have `error: null`

### 💬 Need help?

If you run into issues or have questions, open an issue on the [Apify Store page](https://apify.com/autofacts/youtube-subtitle-transcript-scraper/issues).

***

### 🤖 Use with AI agents

This Actor is callable as a tool by any MCP-capable agent — Claude, Cursor, VS Code — or by your
own code, with no wrapper and nothing extra to deploy.

**Connect over MCP**

```
https://mcp.apify.com?tools=autofacts/youtube-subtitle-transcript-scraper
```

In a client that reads an `mcpServers` configuration block:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=autofacts/youtube-subtitle-transcript-scraper",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

The agent reads this Actor's parameters and their descriptions straight from the input
schema, and the hosted server infers the result field types from the dataset schema — so a
model knows what to send and what comes back before it ever calls anything.

**Or call the API directly**

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

The response body is the dataset records described above.

### 🧰 Other Actors by autofacts

Apify only auto-recommends Actors in the same category, so here are the ones that actually pair with this scraper:

| Actor | What it's for |
| :--- | :--- |
| [TikTok Transcript API & Subtitle Scraper](https://apify.com/autofacts/tiktok-subtitle-transcript-scraper) | TikTok captions and transcripts |
| [Instagram Transcript Scraper](https://apify.com/autofacts/instagram-transcript-scraper) | Instagram Reels turned into text with timestamps |
| [Google Ads Scraper](https://apify.com/autofacts/google-ads-scraper) | A competitor's YouTube video ads, with the video ids to pull their spoken words here |
| [Google Trends Trending Now](https://apify.com/autofacts/google-trends-trending-now) | What is trending on Google right now, in 125 countries, to find the videos worth transcribing |
| [Schema Markup Scraper & SEO Auditor](https://apify.com/autofacts/metadata-scraper) | JSON-LD, Open Graph and a 0-100 SEO audit of any URL |
| [HTML to PDF & URL to PDF API](https://apify.com/autofacts/universal-web-printer) | Turn any URL or HTML into PDF, PNG, JPEG or WebP |
| [Bluesky Scraper](https://apify.com/autofacts/bluesky-scraper) | Posts, profiles, feeds and interactions |

All of them: [apify.com/autofacts](https://apify.com/autofacts)

# Changelog

This Actor's version history is a separate document: https://apify.com/autofacts/youtube-subtitle-transcript-scraper/changelog.md

# Actor input Schema

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

List of YouTube URLs to extract subtitles from. Supports video URLs, Shorts, youtu.be short links, playlist URLs, and channel URLs.

## `startUrls` (type: `array`):

Alternative URL input format. Array of objects with 'url' field.

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

Format for the transcript output.

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

Preferred subtitle languages in order of priority (ISO 639-1 codes, e.g. 'en', 'ja', 'zh-Hans'). Leave empty for any available language.

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

Whether to include YouTube's auto-generated captions if manually-created ones are not available.

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

Maximum number of videos to process (useful for limiting playlist/channel scrapes). 0 = unlimited.

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

Maximum number of videos to process in parallel. Higher values are faster but increase rate-limit risk.

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

YouTube aggressively blocks data-center IPs, so a residential proxy is strongly recommended. Defaults to Apify Residential pinned to the US — residential IPs from low-trust regions get flagged far more often. Change or clear the country to use other regions.

## `youtubeCookies` (type: `string`):

Paste your YouTube cookies to dramatically improve success on videos that trigger 'Sign in to confirm you're not a bot'. Accepts either a raw Cookie header (copy from DevTools → Network → a youtube.com request → Cookie) or a Netscape cookies.txt file (export with a browser extension like 'Get cookies.txt LOCALLY'). If left empty, the actor falls back to a YOUTUBE_COOKIES environment variable — set it as an Apify secret to apply cookies to every run without pasting them each time.

## Actor input object example

```json
{
  "urls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "outputFormat": "json",
  "languages": [
    "en"
  ],
  "includeAutoGenerated": true,
  "maxVideos": 0,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountryCode": "US"
  }
}
```

# Actor output Schema

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

Dataset containing extracted transcripts with timestamps, metadata, and formatted text for each 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 = {
    "urls": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    ],
    "languages": [
        "en"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountryCode": "US"
    }
};

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

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

```

## MCP server setup

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