# YouTube Transcript Extractor - Subtitles in Any Language (`incredible_expertise/youtube-transcript-extractor`) Actor

Get any YouTube video's transcript in the language you choose — clean text, timestamps, and SRT + VTT files, from single videos, playlists or whole channels. Pay ONLY for delivered transcripts: $4.50 per 1,000. Subtitles in any language, Spanish included.

- **URL**: https://apify.com/incredible_expertise/youtube-transcript-extractor.md
- **Developed by:** [Alex Vega](https://apify.com/incredible_expertise) (community)
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.82 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 Extractor — Subtitles & Captions in Any Language

Turn any YouTube video into a **clean, ready-to-use transcript**: the full text plus **timestamped segments**, in the language you choose. Feed single videos, **whole playlists**, or a channel's latest videos — one run handles them all.

**Price: $4.50 per 1,000 transcripts. You pay ONLY for videos that actually return a transcript.** Videos without captions are skipped for free and never appear in your results.

Built for the tools that eat transcripts: AI summarizers, clipping and repurposing pipelines, RAG/agent workflows (works great via the Apify MCP server), researchers, and content teams. English and Spanish are first-class citizens: set your preferred languages in order — e.g. `["en", "es"]` — and for every video you get a **manual caption track whenever one exists**, with YouTube's auto-generated captions only as a flagged fallback.

### How it works

1. **You give inputs**: video URLs or IDs, playlist URLs, and/or channel URLs, plus a cap (`Max videos`).
2. **The Actor fetches each video's captions through yt-dlp plus a local PO-token server** — no browser, no waiting for playback — and picks the best track for your language preferences. Each video is attempted on a fresh residential proxy session and retried on up to 3 sessions if YouTube shows its bot check.
3. **You get one row per video**: full plain-text transcript, timestamped segments, and the video's metadata (title, channel, publish date, duration, views), including which language was actually used and whether the captions are auto-generated.

### What you get per video

| Field | Meaning |
|---|---|
| `transcript` | The full transcript as clean plain text |
| `segments` | `[{startMs, durationMs, text}]` — every caption line with its timing in milliseconds |
| `srt` | The same captions as a complete SubRip (.srt) subtitle file, ready to save or upload |
| `vtt` | The same captions as a complete WebVTT (.vtt) subtitle file |
| `source` | Where the transcript came from: `captions` (extracted directly from the video's caption track) or `api-fallback` (delivered by the optional operator-enabled fallback described below) |
| `language` / `languageName` | The caption language actually delivered (e.g. `en`, `es-419`) and its display name |
| `isAutoGenerated` | `true` if YouTube's automatic (ASR) captions were used, `false` for human-made captions |
| `title`, `channel`, `channelUrl` | Video title and channel |
| `publishedAt`, `durationSeconds`, `viewCount` | Publish date, length and views at extraction time |
| `wordCount`, `characterCount` | Size of the transcript |
| `url`, `videoId`, `thumbnail` | Canonical link, ID and thumbnail |

### Example output (abridged)

```json
{
  "videoId": "arj7oStGLkU",
  "title": "Inside the mind of a master procrastinator | Tim Urban | TED",
  "channel": "TED",
  "language": "en",
  "isAutoGenerated": false,
  "wordCount": 2150,
  "transcript": "I have a confession to make. Both in university and now, I am a huge procrastinator...",
  "segments": [
    {"startMs": 0, "durationMs": 2480, "text": "I have a confession to make."}
  ]
}
```

### Honest expectations

- **A video must have captions to be transcribed.** Most talks, tutorials, podcasts and news videos do (manually or automatically). If a video has no caption track at all, it is skipped and you are not charged. This Actor does **not** download audio or run speech recognition — that keeps it fast and cheap.
- **Private, age-restricted or login-required videos are skipped**, with the reason in the run log.
- **YouTube's bot check is real**: YouTube shows many IPs a "confirm you're not a bot" wall, and some subtitle URLs silently return empty without a per-video integrity (PO) token. The Actor counters with yt-dlp's client rotation, a token server, a fresh **RESIDENTIAL** proxy session per attempt (the default — traffic is tiny, ≈0.2 MB per video) and up to 3 retries per video. A video that still cannot be read is reported honestly in the log as `bot_wall`, `rate_limited` or `no_captions` — and you are never charged for it. Switching the proxy to datacenter saves platform costs at a much lower success rate.
- **Optional operator fallback**: the operator running this Actor can enable a backup layer (via a `TRANSCRIPT_API_KEY`) that retries a video through the third-party TranscriptAPI service only when direct extraction has failed completely. It is off unless the operator turns it on; rows delivered that way are honestly marked with `source: "api-fallback"`.
- Auto-generated captions are YouTube's own quality: usually good for clear speech, weaker for music, heavy accents or overlapping voices. Every result tells you in `isAutoGenerated` which kind you got.
- Language fallback is honest: if none of your preferred languages exists for a video, the first available track is delivered and its real language is reported in `language` — never silently relabeled.

### Inputs at a glance

- **Video URLs or IDs** — watch URLs, `youtu.be` links, Shorts/Live URLs or bare IDs.
- **Playlist URLs** — every video in the playlist, in order.
- **Channel URLs** — the channel's latest videos.
- **Preferred caption languages** — ordered list, default `["en", "es"]`.
- **Include auto-generated captions** — on by default; turn it off to receive only human-made captions.

Questions or a feature request? Message the developer — Spanish and English both welcome.

# Actor input Schema

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

Optional: transcribe the latest videos from these channels (channel page or /videos URL). Combined with Max videos.

## `concurrency` (type: `integer`):

How many videos to process in parallel. Each video runs a full extractor pass; 4 is a good balance of speed and politeness to YouTube's rate limits.

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

If enabled, YouTube's automatic (ASR) captions are used when no manual track matches. Every result flags this in isAutoGenerated. Disable it if you only want human-made captions.

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

Language codes in order of preference, e.g. \["en", "es"] or \["pt-BR"]. For each video the Actor picks a manual caption track in the first matching language; auto-generated captions are the fallback (see below). If no preferred language exists, the first available track is used and the real language is reported in the result.

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

Overall cap of videos processed in this run, across all sources. Trying it out with 25 costs at most about $0.11 in Actor fees (if every video returns a transcript).

## `playlistUrls` (type: `array`):

Optional: transcribe every video in these YouTube playlists (in playlist order, up to Max videos).

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

Standard Apify Proxy settings. Default and strongly recommended: Apify Proxy RESIDENTIAL — YouTube shows its bot check to most datacenter IPs, while residential sessions pass (the Actor also rotates to a fresh session and retries, up to 3 sessions per video, and never charges for a video it could not transcribe). Traffic is tiny (about 0.2 MB per video) and is billed as platform usage. You may switch to datacenter to save platform costs, at a much lower success rate.

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

YouTube videos to transcribe: full watch URLs, youtu.be links, Shorts/Live URLs, or bare 11-character video IDs. The pre-filled value is a ready-to-run example (a popular TED talk with captions in many languages) — replace it with your own videos. You only pay for videos that actually return a transcript.

## Actor input object example

```json
{
  "concurrency": 4,
  "includeAutoGenerated": true,
  "languages": [
    "en",
    "es"
  ],
  "maxVideos": 25,
  "proxyConfiguration": {
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "useApifyProxy": true
  },
  "videoUrls": [
    "https://www.youtube.com/watch?v=arj7oStGLkU"
  ]
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset of video transcripts

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("incredible_expertise/youtube-transcript-extractor").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 = {}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,incredible_expertise/youtube-transcript-extractor"
        }
    }
}
```

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/c1SY6fkktZu1uQ6Bh/builds/9QKYVpvY7dNrSmgdh/openapi.json
