YouTube Transcript & Subtitles Extractor - Text, SRT, VTT avatar

YouTube Transcript & Subtitles Extractor - Text, SRT, VTT

Pricing

from $4.00 / 1,000 transcript fetcheds

Go to Apify Store
YouTube Transcript & Subtitles Extractor - Text, SRT, VTT

YouTube Transcript & Subtitles Extractor - Text, SRT, VTT

Extract YouTube transcripts and subtitles in bulk. Returns plain text, timestamped segments, SRT, VTT, or LLM-ready chunks. Handles auto-generated and human captions in any language. Pay only for videos that return a transcript.

Pricing

from $4.00 / 1,000 transcript fetcheds

Rating

0.0

(0)

Developer

HJL Analytics and AI development

HJL Analytics and AI development

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

YouTube Subtitles & Captions Scraper — Text, SRT, VTT

Download the subtitles of any YouTube video, in bulk, as plain text, timestamped segments, SRT, WebVTT, or chunks ready to feed a language model.

Paste video URLs, get subtitles back. No API key, no browser, no OAuth. You are only charged for videos that actually return a transcript.

What it does

  • Download YouTube subtitles in bulk — hundreds of videos in one run
  • Save YouTube captions as an SRT or VTT subtitle file
  • Get the subtitle track in any language, auto-generated or human-written
  • Extract a YouTube transcript as plain text for summarising, searching, or translating
  • Convert a YouTube video to text without downloading the video itself
  • Prepare subtitles for RAG and LLM pipelines, chunked with timestamps preserved
  • Accepts watch links, youtu.be short links, Shorts, embeds, live URLs, or bare video IDs

Works with every subtitle track YouTube exposes: manually written captions, auto-generated ones, and translated subtitle tracks in any of the languages a video offers.

Output

One row per video. A 19-minute talk looks like this:

{
"videoId": "aircAruvnKk",
"status": "ok",
"title": "But what is a neural network? | Deep learning chapter 1",
"channel": "3Blue1Brown",
"durationSeconds": 1120,
"viewCount": 23919789,
"language": "en",
"isGenerated": false,
"languageMatch": "exact-human",
"cueCount": 286,
"wordCount": 3357,
"text": "This is a 3. It's sloppily written and rendered at an extremely low resolution...",
"chunks": [
{ "index": 0, "text": "This is a 3...", "startSeconds": 4.22, "endSeconds": 71.5, "estimatedTokens": 291 }
]
}

Input

FieldDescription
videoUrlsVideo URLs or 11-character IDs. Duplicates are removed, so the same video pasted twice is charged once.
preferredLanguagesLanguage codes in order, e.g. ["nl", "en"]. Defaults to ["en"].
outputFormatsAny of text, segments, chunks, srt, vtt. Only what you ask for is returned.
chunkTargetCharsTarget chunk size when using chunks. Default 1200.
chunkOverlapCharsContext repeated at each chunk start. Default 100.
includeAvailableLanguagesList every caption language the video offers.
useResidentialProxyOn by default and effectively required — see the note below.
proxyCountryOptional two-letter country code, e.g. US or NL.
maxVideosSafety cap. 0 means no limit.
concurrencyVideos fetched at once. Default 5.

How language selection works

Getting the wrong track is the usual reason a transcript is useless, so the order is explicit:

  1. Your requested language, human-written
  2. Your requested language, auto-generated
  3. A regional variant of it — en-GB when you asked for en
  4. Any human-written track
  5. Anything available

Each result reports which rule applied in languageMatch, so you can tell a precise hit from a fallback rather than guessing.

Human-written beats auto-generated at the same language on purpose: machine captions carry no punctuation and mangle proper nouns, which is exactly what makes a transcript useless further down a pipeline.

LLM-ready chunks

Selecting chunks merges caption fragments into passages of roughly your target size, breaking at sentence ends where possible and keeping the timestamp each passage started at.

That timestamp is the point. It means an answer generated from a chunk can be traced back to a moment in the video, instead of being an unattributable claim. Each chunk also carries a token estimate so you can budget a model call before making it.

When a video fails

Failures are rows, not crashes. One private video in a batch of 500 leaves you with 499 transcripts and one explained failure — and you are not billed for the failure.

errorCodeWhat it meansRetried
NO_CAPTIONSThe video has no caption tracks, or is unavailable or deletedno
LOGIN_REQUIREDThe video is private or age-restricted and needs an accountno
BOT_CHECKYouTube challenged the address the request came fromyes
NETWORK_ERRORThe request never reached YouTubeyes
TIMEOUTYouTube did not answer in timeyes
CAPTIONS_GATEDCaptions exist but sit behind YouTube's proof-of-origin gateno
EMPTY_RESPONSEYouTube accepted the request and returned nothing, which means the same gateno
EMPTY_TRANSCRIPTThe track downloaded but contained no textno
UNREADABLE_INPUTThe input was not a YouTube video URL or IDno

Retryable failures are attempted again from a different proxy address, up to maxRetries times. Permanent ones are not, so a private video never wastes your time or money on retries.

BOT_CHECK and LOGIN_REQUIRED are worth distinguishing because YouTube reports both with the same status code and only the message differs: one means the video needs an account, the other means the exit address was under suspicion. Conflating them fails videos that are perfectly fine.

Honest notes

Playlists and channels are not supported. Supply individual videos. A channel URL returns a clear message rather than a vague parse error.

This relies on YouTube's internal player API, which is undocumented and changes without notice. As of 2026 YouTube gates caption downloads behind a proof-of-origin token that ordinary requests cannot mint; this actor uses a client that is not subject to that gate, and falls back through several others when one stops working. If YouTube closes all of them, transcripts will fail and the actor will need updating — the run log says so explicitly rather than returning an empty result and leaving you to guess.

A residential proxy is required and is on by default. YouTube refuses datacenter address ranges outright, answering every request with "Sign in to confirm you're not a bot". This was measured, not assumed: from a datacenter connection zero of three caption-bearing videos returned a transcript, and the identical code through a residential exit returned all three. Each video uses its own proxy session so a large batch leaves from many addresses rather than concentrating behind one.

Auto-generated captions are approximate. They have no punctuation, guess at proper nouns, and struggle with accents and music. Every result flags isGenerated so you can decide whether that matters for your use.

Local development

npm install
npm test # 40 unit tests, no network
node cli.js https://youtu.be/aircAruvnKk --format text,chunks
node cli.js VIDEO_ID_1 VIDEO_ID_2 --lang nl,en

The CLI runs the same pipeline as the actor, so breakage can be diagnosed locally instead of by spending platform credit.