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

Get transcripts and subtitles from YouTube videos. Charges only for transcripts it actually delivers.

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

## Pricing

$20.00 / 1,000 transcript delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

Get the transcript of any YouTube video that has subtitles — as plain text, timestamped segments, SRT or WebVTT. Built for feeding video content into LLMs, RAG pipelines, summarizers and search indexes.

**You are charged $0.02 for each transcript actually delivered.** No charge for starting the run. No charge for videos that turn out to have no subtitles, that are private, or that fail. If a run returns nothing, it costs nothing.

### Why this one

Most YouTube transcript scrapers use a single extraction path. YouTube has been tightening that path through 2025 and 2026, which is why published failure rates in this category sit around 11%. This Actor tries three paths per video, in order of cost:

1. YouTube's own player API through residential IPs
2. The video watch page
3. A real browser session, for the videos the first two cannot reach

One video failing never fails the run. Every video comes back with either a transcript or a specific reason.

### Input

| Field | What it does |
|---|---|
| `videoUrls` | Video URLs or 11-character IDs. Watch, Shorts, live and `youtu.be` links all work. |
| `languages` | Preferred language codes in order, e.g. `["en","es"]`. Manual subtitles are preferred over auto-generated ones in the same language. Falls back to any available track. |
| `outputFormat` | `plain`, `segments`, `srt`, `vtt`, or `all`. |
| `includeVideoDetails` | Adds title, channel, duration and view count. |
| `maxConcurrency` | Videos processed at once. Default 5. |
| `useBrowserFallback` | Leave on for maximum success rate. Turn off for the fastest possible run. |

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=aircAruvnKk", "jNQXAC9IVRw"],
  "languages": ["en"],
  "outputFormat": "all"
}
```

### Output

One dataset item per video.

```json
{
  "videoId": "aircAruvnKk",
  "url": "https://www.youtube.com/watch?v=aircAruvnKk",
  "transcriptAvailable": true,
  "language": "en",
  "isAutoGenerated": false,
  "availableLanguages": ["en", "es", "ja"],
  "segmentCount": 412,
  "wordCount": 3187,
  "text": "full transcript as one string",
  "segments": [{ "start": 0.5, "dur": 2.2, "text": "line of speech" }],
  "srt": "1\n00:00:00,500 --> 00:00:02,700\nline of speech\n",
  "vtt": "WEBVTT\n\n00:00:00.500 --> 00:00:02.700\nline of speech\n",
  "video": { "title": "...", "channel": "...", "durationSeconds": 1140, "viewCount": 18400000 }
}
```

A video without a usable transcript still produces an item, with `transcriptAvailable: false` and an `error` naming the reason — no captions, unavailable, age-restricted, or a fetch failure. These items are free.

### What it does not do

- It cannot transcribe audio. If a video has no subtitle track of any kind, there is nothing to return. Roughly speaking, most talk-based videos have at least auto-generated captions; music and very new uploads often do not.
- It does not download video or audio.
- It does not work on private, deleted or members-only videos.
- Translated subtitle tracks are returned as published by YouTube; no machine translation is applied on top.

### Using it from code

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

const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('YOUR_USERNAME/youtube-transcript-scraper').call({
  videoUrls: ['https://www.youtube.com/watch?v=aircAruvnKk'],
  outputFormat: 'plain',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].text);
```

Runs work the same way over the API, on a schedule, or through any integration Apify supports.

### Data and legal

Subtitles are public content served by YouTube to ordinary viewers. This Actor requests them the way a normal client does; it does not defeat access controls and it does not touch private data or user accounts. You are responsible for how you use the output, including any copyright that applies to the underlying video.

# Actor input Schema

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

Video URLs or 11-character video IDs. Accepts watch, shorts, live and youtu.be links.

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

Language codes in order of preference, e.g. en, es, ja. Manual subtitles win over auto-generated ones in the same language. Falls back to any available track.

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

plain = one text field. segments = timestamped lines. srt / vtt = subtitle file text.

## `includeVideoDetails` (type: `boolean`):

Add title, channel, duration and view count to each result.

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

How many videos to process at once.

## `useBrowserFallback` (type: `boolean`):

When the fast paths are blocked, open the video in a real browser to recover the transcript. Slower, and only used for videos that would otherwise fail.

## `useResidentialProxy` (type: `boolean`):

Route requests through residential IPs. Turn it off to run cheaper when the datacenter IP is not blocked.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=aircAruvnKk"
  ],
  "languages": [
    "en"
  ],
  "outputFormat": "all",
  "includeVideoDetails": true,
  "maxConcurrency": 5,
  "useBrowserFallback": true,
  "useResidentialProxy": true
}
```

# Actor output Schema

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

All items, including the videos that had no captions, with the reason in the error field.

## `plainText` (type: `string`):

Video, language and the full transcript text as one column per row. Convenient for spreadsheets and LLM input.

## `timedSegments` (type: `string`):

Transcripts with per-line start time and duration, for subtitles and video search.

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

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

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

```

## MCP server setup

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