YouTube Transcript Scraper - Captions & Subtitles API avatar

YouTube Transcript Scraper - Captions & Subtitles API

Pricing

from $1.99 / 1,000 results

Go to Apify Store
YouTube Transcript Scraper - Captions & Subtitles API

YouTube Transcript Scraper - Captions & Subtitles API

📝 YouTube Transcript Scraper extracts timestamped transcripts, captions & subtitles from any public video in 18 languages — plus title, channel & view data. ⚡ No API key. 🚀 Perfect for AI pipelines, SEO & repurposing. ✅

Pricing

from $1.99 / 1,000 results

Rating

0.0

(0)

Developer

Scrapers Hub

Scrapers Hub

Maintained by Community

Actor stats

0

Bookmarked

5

Total users

1

Monthly active users

a day ago

Last modified

Share

YouTube Transcript Scraper — Timestamped Captions, Subtitles and Video Metadata

YouTube Transcript Scraper pulls the full timestamped transcript out of any public YouTube video, in 18 languages, without an API key, OAuth client, or a logged-in Google account. Paste one watch URL or a hundred, pick a language, and every video comes back as a structured record: the transcript as an array of text + timestamp segments, plus the video title, channel name, subscriber count, view count, and publish date. Output is clean JSON, ready to hand to an LLM, drop into a spreadsheet, or push through a summarization pipeline. Built for teams who need the actual spoken content of a video as data — not a link to it.

🤔 What is YouTube Transcript Scraper?

YouTube Transcript Scraper is a caption-extraction Actor that reads YouTube's own public transcript tracks and returns them as structured, timestamped data. It needs no Google Cloud project, no YouTube Data API quota, and no login — only a video URL. Where the official YouTube Data API makes captions available only to the video's owner under OAuth, this Actor reads the same publicly rendered caption tracks a viewer sees when they click "Show transcript," including auto-generated ASR captions.

Alongside the transcript, each record carries the video metadata scraped from the watch page itself, so you don't need a second API call to know whose channel a transcript came from or how many views it had at scrape time.

  • Timestamped transcript extraction — every caption line returned as {text, timestamp} in M:SS form
  • 18 language options with automatic fallback when your first choice isn't published
  • Video metadata in the same record — title, channel, subscriber count, views, publish date
  • Automatic proxy rotation on YouTube IP blocks, with a fresh residential exit IP per video
  • Per-video fault isolation — one dead video never kills the rest of your batch
  • Both URL forms acceptedyoutube.com/watch?v= and short youtu.be/ links

How YouTube Transcript Scraper handles language fallback

The language field takes a two-letter code, but YouTube doesn't publish every language for every video, so the Actor degrades in a defined order rather than returning nothing. It first looks for a transcript matching your requested code (or a regional variant of it, so en also matches en-US). If that isn't published, it falls back to English. If English isn't there either, it falls back to any auto-generated English track. Failing all three, it takes the first transcript track the video offers in any language.

That means a run against a batch of mixed-language videos returns transcripts for nearly all of them rather than silently dropping the ones that don't match your setting — but it also means a returned transcript is not guaranteed to be in the language you asked for. If language purity matters for your downstream pipeline, check the text before trusting the code.

📦 What data can you get with YouTube Transcript Scraper?

Every run produces one dataset row per video URL, combining the caption track with the watch-page metadata.

Result typeExtracted fieldsPrimary use case
Transcript segmentstranscript[].text, transcript[].timestampSummarization, search indexing, RAG chunking, subtitle files
Video metadatavideoTitle, channelName, channelSubscription, views, videoPostDateAttribution, ranking, channel-level analysis, dataset filtering
Request recordurlJoining results back to your input list

Timestamped segments, not a wall of text

The transcript field is an array, not a single string. Each element is one caption cue with its own start time formatted as M:SS"0:42", "12:07". This is deliberate and it's the field that does the most work downstream.

Because each line keeps its offset, you can chunk a transcript by time window for a RAG index, deep-link a viewer to the exact moment a phrase was spoken (&t= on the watch URL), rebuild an SRT or WebVTT subtitle file, or align a transcript against engagement data to see which minute of a video people actually watched. A flattened transcript string throws all of that away. If you do want plain prose, joining the text values is one line of code — the reverse is impossible.

{
"transcript": [
{ "text": "(light cheerful music)", "timestamp": "0:03" },
{ "text": "♪ I don't want a lot for Christmas ♪", "timestamp": "0:10" },
{ "text": "♪ There is just one thing I need ♪", "timestamp": "0:16" }
]
}

Channel and view metadata

Metadata is parsed from the watch page's own ytInitialPlayerResponse and ytInitialData payloads using a brace-matching JSON extractor rather than a regex, so nested objects and escaped strings inside the blob don't truncate the parse. views comes back as a human-formatted string ("908,020,767 views") and channelSubscription as YouTube's own abbreviated form ("13M subscribers") — parse them to integers yourself if you need arithmetic. If YouTube serves a stripped page to a particular exit IP, the Actor rotates to a new one and retries up to three times before returning null metadata with the transcript still intact.

🆚 How does YouTube Transcript Scraper differ from the official YouTube Data API?

This is the comparison that matters most, because the official API technically has a captions endpoint — it just won't give you other people's captions.

FeatureYouTube Data API v3YouTube Transcript Scraper
Access requirementGoogle Cloud project, API key, OAuth 2.0 clientNone — no key, no login, no quota project
Third-party captionscaptions.download only works for videos you ownReads any public video's published caption track
Auto-generated (ASR) captionsNot downloadable via the APIReturned like any other track
QuotaDaily units; caption calls are expensiveNo Google quota — billed per result on Apify
MetadataSeparate videos.list call you write and join yourselfTitle, channel, subs, views, date in the same row
Blocked requestsYour client handles backoffAutomatic residential proxy rotation and retry
Output shapeRaw caption file (SBV/SRT) you parseNormalized {text, timestamp} JSON array

Use the official Data API when you're managing your own channel's captions, uploading subtitle tracks, or need fields the watch page doesn't expose. Use YouTube Transcript Scraper when you need the spoken content of videos you don't own, in bulk, as structured data — which is what most research, summarization, and content-analysis work actually requires.

🚀 How to scrape YouTube transcripts with YouTube Transcript Scraper?

  1. Open the youtube-transcript-scraper Actor in Apify Console and click Try for free.
  2. Paste one or more YouTube video URLs into startUrls. Both https://www.youtube.com/watch?v=ID and https://youtu.be/ID are accepted.
  3. Pick a language from the dropdown — English is the default.
  4. Click Start and watch the run log; each URL is logged as it's processed.
  5. Open the Dataset tab and export as JSON, CSV, or Excel, or pull it through the Apify API.

A complete run needs exactly one field:

{
"startUrls": [
{ "url": "https://www.youtube.com/watch?v=aAkMkVFwAoo" }
],
"language": "en"
}

Running a batch of videos in one job

startUrls accepts an array of any length, and every entry is processed within the same run. Videos are handled sequentially, each on its own freshly rotated proxy IP, so a 50-URL batch takes roughly 50× the single-video time rather than finishing in parallel. In testing, a single video completed in about 11 seconds end to end, so plan for roughly nine to ten videos per minute and set your run timeout accordingly on large batches.

Crucially, each video is wrapped in its own error boundary. A private video, a deleted video, a livestream with no caption track, or a malformed URL is logged and skipped — the run continues and the rest of your batch still lands in the dataset. You will not lose 49 transcripts because the 50th URL was bad.

⬇️ Input

YouTube Transcript Scraper takes one required field. Everything else has a working default.

ParameterRequiredTypeDescriptionExample value
startUrlsYesarrayYouTube video URLs to scrape. Accepts {"url": "..."} objects or plain strings. Both youtube.com/watch?v= and youtu.be/ forms work.[{"url": "https://www.youtube.com/watch?v=aAkMkVFwAoo"}]
languageNostring (select)Preferred transcript language code. One of en, de, hi, nl, pl, tr, vi, id, es, fr, it, pt, ru, ja, ko, zh-Hans, ar, bn. Default "en"."es"
proxyConfigurationNoobjectApify Proxy settings. Not exposed in the Console form — settable only through the API or a task's raw input. Defaults to Apify residential proxies, which is the recommended setting.{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}
{
"startUrls": [
{ "url": "https://www.youtube.com/watch?v=aAkMkVFwAoo" },
{ "url": "https://youtu.be/dQw4w9WgXcQ" }
],
"language": "en"
}

Pitfall: proxyConfiguration is read by the Actor but is not declared in its input schema, so it never appears in the Console's input form. If you leave it alone you get residential proxies automatically, which is what you want — YouTube blocks datacenter IPs aggressively for caption requests. You only need to set it explicitly (via API or a saved task) if you want a specific proxy group or country, and setting useApifyProxy: false will noticeably increase the rate of empty transcripts.

Second pitfall: an invalid URL that contains no extractable video ID is logged as an error and skipped entirely — it produces no dataset row at all, rather than a row with null fields. If your output row count is lower than your input URL count, check the run log for Invalid YouTube URL lines before assuming the transcripts were missing.

⬆️ Output

One dataset row per successfully processed video, in a stable schema across runs. Export as JSON, CSV, or Excel, or fetch it from the Apify API.

Scraped results

[
{
"url": "https://www.youtube.com/watch?v=aAkMkVFwAoo",
"videoTitle": "Mariah Carey - All I Want for Christmas Is You (Make My Wish Come True Edition)",
"channelName": "MariahCareyVEVO",
"channelSubscription": "13M subscribers",
"views": "908,020,767 views",
"videoPostDate": "2019-12-19T21:00:11-08:00",
"transcript": [
{ "text": "(light cheerful music)", "timestamp": "0:03" },
{ "text": "♪ I don't want a lot for Christmas ♪", "timestamp": "0:10" },
{ "text": "♪ There is just one thing I need ♪", "timestamp": "0:16" },
{ "text": "♪ I don't care about the presents ♪", "timestamp": "0:21" }
]
}
]

A note on partial results: metadata and transcript are fetched independently, so a row can legitimately arrive with a full transcript and null metadata (YouTube served a stripped page), or with complete metadata and an empty transcript array (the video genuinely has no captions published, or captions are disabled). Treat transcript: [] as "no captions on this video," not as an error.

💡 How can I use the data extracted with YouTube Transcript Scraper?

  • AI and LLM engineers: chunk transcript by timestamp window and embed it for a retrieval index, so an agent can answer questions grounded in what was actually said in a video and cite the minute it was said.
  • Content and SEO teams: turn long-form video into blog drafts, show notes, or timestamped chapter markers, and mine the transcript for the phrases your audience already uses.
  • Media researchers and analysts: scrape a channel's back catalogue and track how the language around a topic shifts over time, using videoPostDate and channelName to segment.
  • Accessibility and localization teams: pull existing caption tracks in bulk to audit coverage, spot videos missing captions entirely, or seed a translation workflow.
  • Market and competitor researchers: extract what competitors say in their own product videos and webinars, with views and channelSubscription as a rough reach weighting.

📈 How do you monitor a YouTube channel's transcripts over time?

Monitoring here means re-running the same URL set on a schedule and diffing, rather than treating each run as a one-off. Transcripts themselves rarely change once published, so the fields worth watching are the metadata: views and channelSubscription both move continuously, and comparing them across runs turns a static transcript archive into a performance dataset.

The practical workflow is to keep a list of video URLs, schedule YouTube Transcript Scraper to re-run it on a fixed interval, and join each run's output to the previous one on url. Rising views against a stable transcript tells you which spoken content is actually earning watch time. A transcript that changes between runs means the creator re-uploaded or re-captioned the video — worth flagging in a competitive-intelligence context.

To follow a whole channel rather than a fixed URL list, pair this Actor with a channel or playlist scraper that discovers new video URLs, then feed those URLs in. Apify Console's built-in Schedule feature triggers the run on an interval, and a run-completion webhook can push each new batch straight into your own pipeline.

🔌 Integrate YouTube Transcript Scraper into your workflow

YouTube Transcript Scraper is callable from anything that can make an HTTP request.

🐍 REST API with Python

import requests
TOKEN = "YOUR_APIFY_TOKEN"
url = f"https://api.apify.com/v2/acts/scrapers-hub~youtube-transcript-scraper/run-sync-get-dataset-items?token={TOKEN}"
payload = {
"startUrls": [{"url": "https://www.youtube.com/watch?v=aAkMkVFwAoo"}],
"language": "en",
}
videos = requests.post(url, json=payload).json()
for video in videos:
full_text = " ".join(seg["text"] for seg in video["transcript"])
print(video["videoTitle"], "-", len(full_text), "characters")

🤖 MCP for AI agents

The Actor is reachable through Apify's Actors MCP Server, so an MCP-compatible client — Claude Desktop, Claude.ai, VS Code — can call it as a tool and ground its answer in a real transcript. Register it with npx @apify/actors-mcp-server --tools scrapers-hub/youtube-transcript-scraper with your APIFY_TOKEN set, or connect to the hosted endpoint at https://mcp.apify.com.

⏰ Scheduled runs and webhooks

Use Apify Console's Schedule tab to run the Actor on a recurring interval with no cron server of your own, and attach a webhook on run completion to pull each finished dataset into your warehouse or vector store automatically.

💰 Pricing

This Actor is billed per result — one charge per video record pushed to the dataset — on top of Apify platform usage. Videos that fail entirely and produce no row are not charged as results. Current per-result pricing is shown on the Actor's Apify Store page; check there for the live figure rather than relying on any number quoted in documentation.

YouTube Transcript Scraper reads only publicly accessible caption tracks and watch-page data — the same content any visitor sees without logging in. Courts have held that scraping publicly available web data does not violate the U.S. Computer Fraud and Abuse Act (hiQ Labs, Inc. v. LinkedIn Corp., 9th Cir. 2019, reaffirmed 2022), though YouTube's own Terms of Service separately govern permitted use of the platform. Transcripts are creative content owned by the uploader: extracting them for analysis, search, and research is a different matter from republishing them verbatim, and copyright still applies to the underlying work. Consult your legal team before redistributing scraped transcripts or using them commercially at scale.

❓ Frequently asked questions

Does YouTube Transcript Scraper need an API key or Google account?

No. It reads YouTube's public caption tracks and watch pages directly — no API key, OAuth client, Google Cloud project, or login of any kind.

Can it download auto-generated captions?

Yes. Auto-generated (ASR) tracks are treated like any other transcript, and are used as an explicit fallback when no manually written track exists in your requested language. This is the main thing the official YouTube Data API cannot do for videos you don't own.

What languages are supported?

Eighteen: English, German, Hindi, Dutch, Polish, Turkish, Vietnamese, Indonesian, Spanish, French, Italian, Portuguese, Russian, Japanese, Korean, Simplified Chinese, Arabic, and Bengali. If your chosen language isn't published for a video, the Actor falls back to English, then auto-generated English, then the first available track.

Why is the transcript array empty for some videos?

Because that video has no published captions — they were disabled by the uploader, or none were ever generated. An empty transcript array with populated metadata is a valid result, not a failure. Livestreams and very new uploads are the most common cases.

Why is my metadata null but the transcript populated?

The watch page and the caption track are fetched through separate requests. If a proxy exit IP receives a stripped page, the Actor retries on a fresh IP up to three times, then returns null metadata rather than discarding the transcript it already has.

How many videos can I scrape in one run?

There's no hard cap in the input — startUrls takes as many URLs as you want to paste. Videos are processed sequentially at roughly nine to ten per minute, so size your run timeout to match the batch.

Can I get an SRT or VTT subtitle file out of it?

Not directly, but the output contains everything needed to build one. Each cue's text and start time are preserved, so generating SRT or WebVTT is a short formatting step over the transcript array.

Yes. Both youtube.com/watch?v=ID and youtu.be/ID are parsed for the video ID. Playlist and channel URLs are not — feed those through a playlist or channel scraper first to expand them into video URLs.

How does it handle YouTube blocking?

It routes through Apify residential proxies by default and takes a fresh exit IP for every video. When YouTube blocks a request outright, the Actor rotates to a new IP and retries up to three times before giving up on that video and moving to the next.

Can I use it with Claude, ChatGPT, or an agent framework?

Yes. It's a plain HTTP endpoint from any framework, and it's registered on Apify's Actors MCP Server so MCP clients can call it directly as a tool.

Does one bad URL break the whole run?

No. Every video is processed inside its own error boundary — invalid URLs, private videos, and unexpected failures are logged and skipped while the rest of the batch completes normally.

Pair YouTube Transcript Scraper with the rest of the YouTube toolkit to go from a channel to full-text transcripts in two steps:

  • Youtube Channel Video Scraper — enumerate every video URL on a channel, then feed them in here
  • Youtube Playlist Scraper — expand a playlist into video URLs for bulk transcription
  • Youtube Video Downloader — grab the media file itself alongside its transcript
  • TikTok Subtitles Extractor — the same timestamped-caption workflow for TikTok videos

💬 Your feedback

Found a video where the transcript comes back empty but captions clearly exist, or a metadata field that stopped parsing? Report it through the Issues tab on this Actor's Apify Console page. YouTube changes its watch-page payloads without notice, and those reports are how the extraction logic keeps matching reality.

Prefer email? Contact the team directly at scraperhubapi@gmail.com. Include the Actor name, the exact input you used, and the run ID so the issue can be reproduced and fixed quickly.