# YouTube Transcript Scraper — Captions & Subtitles, Cheap (`fabrikit/youtube-transcript-scraper`) Actor

Get YouTube transcripts and subtitles for videos, channels, playlists or search results. Manual captions preferred, auto-generated as fallback, any language, optional translation. Output as timed segments, plain text, SRT or VTT. No API key. From US$1 per 1,000 videos.

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

## Pricing

from $1.00 / 1,000 transcript returneds

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 — Captions & Subtitles, Cheap

Get the transcript of any YouTube video, or of every video in a channel, playlist or search, as clean text, timed segments, SRT or WebVTT. No API key, no login, no browser.

### What you get

- **Transcripts for videos, channels, playlists and searches.** Paste video URLs or IDs, a channel (`/@handle`), a playlist or a results page, or just type search queries.
- **Manual captions first.** For each language you list, the creator's own captions are preferred over auto-generated ones. Turn auto-generated captions off if you only want human-made ones.
- **Language control.** Give an ordered list (`en`, `es`, `pt-BR`...), fall back to any available language, and see every available track in `availableLanguages`.
- **Four output formats.** Timed segments (`start`, `duration`, `text`), plain text, an SRT file or a WebVTT file.
- **Metadata included.** Title, channel, publish date, duration, word count.
- **Pay only for transcripts.** Videos without captions are reported (status `no_captions`) but never billed.

### Input

| Field | Description |
|---|---|
| `startUrls` | Video URLs/IDs, channels, playlists, search URLs (one per line) |
| `searchQueries` | Keywords; only videos with subtitles are returned |
| `maxItems` | Max transcripts returned and billed (default 20) |
| `maxVideosPerSource` | Videos read from each channel/playlist/search (default 20) |
| `languages` | Preferred language codes in order (default `["en"]`) |
| `includeAutoGenerated` | Allow auto-generated captions (default on) |
| `fallbackToAnyLanguage` | Use another language if none of yours exist (default on) |
| `translateTo` | Optional target language code. Best effort, see FAQ |
| `outputFormat` | `segments`, `text`, `srt`, `vtt` or `all` |
| `proxyConfiguration` | Datacenter by default; escalates to residential automatically if YouTube asks for a bot check |

Example:

```json
{
  "startUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ", "https://www.youtube.com/@TED/videos"],
  "languages": ["en", "es"],
  "maxItems": 50,
  "maxVideosPerSource": 25,
  "outputFormat": "segments"
}
```

### Output

```json
{
  "videoId": "jNQXAC9IVRw",
  "url": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
  "title": "Me at the zoo",
  "channelName": "jawed",
  "language": "en",
  "isAutoGenerated": false,
  "status": "ok",
  "transcript": "All right, so here we are, in front of the elephants ...",
  "segments": [{ "start": 1.2, "duration": 2.16, "text": "All right, so here we are, in front of the elephants" }],
  "wordCount": 39,
  "durationSeconds": 19,
  "availableLanguages": [{ "languageCode": "en", "languageName": "English", "isAutoGenerated": false, "isTranslatable": true }]
}
```

`status` is `ok`, `no_captions` (no matching track), `unavailable` (private, removed, age-gated) or `error`.

### Pricing

| Event | Price |
|---|---|
| Transcript returned | **US$1.00 per 1,000 videos** |

Videos without captions and failed videos are free. Set a maximum cost per run and the Actor stops exactly at your limit.

### FAQ

**Does it need a YouTube API key?** No.
**Which videos work?** Any public video that has captions (manual or auto-generated). Private, deleted and age-restricted videos are reported as unavailable.
**Can it transcribe audio when there are no captions?** No. It reads existing captions only.
**Does translation work?** `translateTo` uses YouTube's own caption translation. YouTube rate-limits it aggressively, so when it is refused the Actor returns the original language and says so in `error`.
**Is it fast?** About 250 transcripts in 90 seconds on a laptop.

### Use cases

Training and RAG datasets, summarisation, SEO and content repurposing, topic research across a channel, subtitle files for editors, accessibility.

### En español

Obtén la transcripción de cualquier video de YouTube, o de todos los videos de un canal, lista o búsqueda, como texto, segmentos con tiempo, SRT o VTT. Prefiere los subtítulos manuales sobre los automáticos, permite elegir idioma y no necesita API key. Solo pagas por transcripciones entregadas: US$1 por cada 1.000 videos.

# Actor input Schema

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

One entry per line: video URLs (watch, youtu.be, shorts, live, embed) or bare 11-character video IDs, channel URLs / `@handles`, playlist URLs or search-result URLs. Channels, playlists and searches are expanded into videos (see *Max videos per channel / playlist / search*).

## `searchQueries` (type: `array`):

Keywords to search on YouTube. Only videos with subtitles are returned. Each query expands to up to *Max videos per channel / playlist / search* videos.

## `maxItems` (type: `integer`):

Hard cap on transcripts returned (and billed) in the whole run. Videos without captions are reported for free and do not count.

## `maxVideosPerSource` (type: `integer`):

How many videos to read from each channel, playlist, search URL or search query.

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

Language codes in order of preference (e.g. `en`, `es`, `pt-BR`). For each language a manual caption is preferred over an auto-generated one. `en` also matches `en-GB` etc.

## `fallbackToAnyLanguage` (type: `boolean`):

If none of the preferred languages exists, return the first available track instead of reporting the video as having no matching captions.

## `translateTo` (type: `string`):

Language code to machine-translate the transcript into (e.g. `es`, `en`, `zh-Hant`) using YouTube's own translation. Leave empty to keep the original language. Only works when the source track is translatable.

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

When off, only captions uploaded by the creator are returned.

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

`segments`: plain text plus timed segments (start, duration, text). `text`: plain text only. `srt` / `vtt`: plain text plus a ready-to-save subtitle file. `all`: everything.

## `mergeRepeatedLines` (type: `boolean`):

Auto-generated captions often repeat the same line in consecutive segments. Merge those duplicates.

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

Datacenter proxy by default. If YouTube asks for a bot check, the Actor automatically switches to Residential proxies for the rest of the run.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://www.youtube.com/watch?v=jNQXAC9IVRw"
  ],
  "searchQueries": [],
  "maxItems": 20,
  "maxVideosPerSource": 20,
  "languages": [
    "en"
  ],
  "fallbackToAnyLanguage": true,
  "translateTo": "",
  "includeAutoGenerated": true,
  "outputFormat": "segments",
  "mergeRepeatedLines": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All transcripts collected during the run

# 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 = {
    "startUrls": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        "https://www.youtube.com/watch?v=jNQXAC9IVRw"
    ],
    "maxItems": 20,
    "maxVideosPerSource": 20,
    "languages": [
        "en"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("fabrikit/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 = {
    "startUrls": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        "https://www.youtube.com/watch?v=jNQXAC9IVRw",
    ],
    "maxItems": 20,
    "maxVideosPerSource": 20,
    "languages": ["en"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("fabrikit/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 '{
  "startUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://www.youtube.com/watch?v=jNQXAC9IVRw"
  ],
  "maxItems": 20,
  "maxVideosPerSource": 20,
  "languages": [
    "en"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call fabrikit/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

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