YouTube Transcript Scraper - Subtitles, Captions & Timestamps avatar

YouTube Transcript Scraper - Subtitles, Captions & Timestamps

Pricing

from $2.00 / 1,000 transcript delivereds

Go to Apify Store
YouTube Transcript Scraper - Subtitles, Captions & Timestamps

YouTube Transcript Scraper - Subtitles, Captions & Timestamps

Extract YouTube transcripts and subtitles from any video, channel, playlist or search. Plain text, timestamps, SRT, VTT and RAG-ready chunks with real timings. No API key, no cookies, no browser.

Pricing

from $2.00 / 1,000 transcript delivereds

Rating

0.0

(0)

Developer

Team Sasuke

Team Sasuke

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

YouTube Transcript Scraper — Subtitles, Captions & Timestamps

Get the transcript of any YouTube video as text, timestamped segments, SRT, VTT or chunks ready to embed. Point it at a video, a whole channel, a playlist or a search term and it returns every transcript behind it.

No API key. No login cookie. No headless browser. Proxy included and configured by default.


Why this one works when others return blank rows

In 2025 YouTube began requiring a proof-of-origin token on caption downloads made through its public web client. Requests without one still get HTTP 200 — with an empty body. That is why so many transcript tools now return rows with the metadata filled in and the transcript field empty, and why "it worked last month" is such a common complaint.

This scraper talks to two YouTube clients that are still exempt from that requirement, so caption URLs download normally with no token and no browser.

The second half of the problem is where the request comes from. YouTube challenges cloud datacenter addresses with "Sign in to confirm you're not a bot", and a challenged address stays challenged. So every worker here holds its own proxy address, and the moment one is challenged it is thrown away and the video retried on a fresh one.

Measured on the same 25-video channel:

SettingTranscripts returned
No proxy0 of 25
Datacenter proxies24 of 25
Residential proxies (default)25 of 25

In testing, the only videos that came back without a transcript were private, deleted, or genuinely had captions turned off — and the run says which, and why.

Apart from a small fixed fee when a run starts, you only pay for transcripts you actually receive. Videos with no captions, private videos and dead links cost you nothing.


What you can feed it

Paste thisYou get
https://www.youtube.com/watch?v=VIDEO_IDthat video
https://youtu.be/VIDEO_IDthat video
https://www.youtube.com/shorts/VIDEO_IDthat Short
https://www.youtube.com/@channelevery video on the channel
https://www.youtube.com/playlist?list=PLAYLIST_IDthe whole playlist
machine learning basics in Search termstop results for the term
dQw4w9WgXcQa bare video ID works too

Channels and playlists page automatically — ask for 500 videos and it collects 500, as long as the channel has that many. Use Max videos per channel, playlist or search to set the ceiling.


What each row contains

{
"videoId": "M7lc1UVf-VE",
"url": "https://www.youtube.com/watch?v=M7lc1UVf-VE",
"title": "YouTube Developers Live: Embedded Web Player Customization",
"channelName": "Google for Developers",
"channelUrl": "https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw",
"durationSeconds": 1667,
"viewCount": 234571,
"description": "...",
"keywords": ["youtube api", "embed"],
"thumbnailUrl": "https://i.ytimg.com/vi/M7lc1UVf-VE/maxresdefault.jpg",
"language": "en",
"languageName": "English",
"isAutoGenerated": false,
"isTranslated": false,
"availableLanguages": ["en", "es"],
"transcript": "JEFF POSNICK: Hey, everybody. Welcome to this week's show...",
"wordCount": 3778,
"characterCount": 21044,
"segmentCount": 466,
"segments": [
{ "start": 10.349, "duration": 1.0, "end": 11.349, "text": "JEFF POSNICK: Hey, everybody." }
],
"sourceType": "channel",
"sourceInput": "https://www.youtube.com/@GoogleDevelopers",
"scrapedAt": "2026-09-09T18:22:04+00:00",
"error": null
}

srt, vtt and chunks are added when you switch them on.


Built for AI pipelines

Turn on Split transcript into chunks and each transcript comes back already divided into overlapping passages sized for an embedding model — and every chunk keeps the real start and end time of the passage it covers:

"chunks": [
{ "index": 0, "start": 10.349, "end": 58.17, "text": "JEFF POSNICK: Hey, everybody..." },
{ "index": 1, "start": 54.02, "end": 96.44, "text": "...so the first thing we do is..." }
]

That timestamp is the part most tools drop. Keeping it means your RAG answers can cite the exact moment in the video, and your users can click straight to it at https://youtu.be/VIDEO_ID?t=54.

Chunks are built from whole caption lines, never by cutting at a fixed character count, so sentences stay intact.


Common uses

  • Feed a RAG or LLM pipeline — chunked, timestamped, citable.
  • Summarise a whole channel — competitor research, podcast archives, conference talks.
  • Repurpose video into written content — blog posts, newsletters, show notes.
  • Subtitle files — export SRT or WebVTT for editors and players.
  • Translate — have YouTube translate the transcript into another language.
  • Keyword and SEO research — search what is actually said, not just titles.
  • Accessibility and compliance — archive spoken content as text.

Languages

Set Preferred caption languages in order, for example en, es, fr. Regional variants match automatically, so en accepts en-US and en-GB.

When a video offers both human-written and auto-generated captions, the human ones are used by default — they are meaningfully more accurate with names, jargon and numbers. Turn off Prefer human-written captions to take whichever comes first.

Set Translate transcript to for a machine translation into any language YouTube supports. If translation is unavailable for a video, you get the original transcript rather than an empty row.


Speed

In testing, 58 videos across a channel, a playlist and a search finished in 40 seconds, container start-up included. Speed varies with video length and with how hard YouTube is rate-limiting at the time. Raising concurrency helps up to a point, then YouTube begins rate-limiting; the scraper backs off and retries rather than dropping rows.


Use it as an API

Every run is callable over HTTP. Start a run and collect the dataset:

curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~youtube-transcript-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
"chunkSize": 1000,
"chunkOverlap": 150
}'

Python:

from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("YOUR_USERNAME/youtube-transcript-scraper").call(run_input={
"videoUrls": ["https://www.youtube.com/@channel"],
"maxVideosPerSource": 100,
"languages": ["en"],
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["title"], item["wordCount"])
print(item["transcript"][:200])

Works the same from JavaScript, n8n, Make, Zapier and LangChain.


Limits, stated plainly

  • A video must have captions. This reads YouTube's caption tracks; it does not transcribe audio. Most videos over a few minutes have at least auto-generated captions, but some creators disable them.
  • Private, deleted, members-only and age-restricted videos cannot be read. The run log gives the reason, and that video is not charged. Turn on List videos with no transcript to also save every such video, with its reason, to the run's key-value store.
  • Auto-generated captions have no punctuation on some videos. That is how YouTube produces them, not a fault in the output.
  • Live streams only have transcripts once the recording is processed.
  • A proxy is required on the platform. It is already configured; you only need to touch it if you want to switch residential for datacenter.

Pricing

A small fixed fee when a run starts, then a charge per transcript delivered. Videos with no captions, private videos and failed lookups are free.

Start a run with the defaults and see what comes back — the sample input is already filled in.