YouTube Transcript Scraper
YouTube transcripts from links or a keyword search: text, timed segments, SRT, VTT and video details. No API key. $0.80 per 1,000.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
videoUrls,videoIds,searchKeywords(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.0008 per transcript = $0.8 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Transcript extracted | One successfully extracted transcript. Failed or unavailable videos are not charged. | $0.0008 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-09-30, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
videoUrls | YouTube watch, Shorts, live, embed, or youtu.be URLs. Raw 11-character video IDs are also accepted. Duplicate videos are processed once. | array |
videoIds | Optional additional list of raw 11-character YouTube video IDs. This is useful for programmatic runs that already have IDs. | array |
searchKeywords | Search YouTube and get transcripts for the videos it finds, one search per line. Use it on its own or next to links: a video that turns up twice is fetched once. | array |
maxVideosPerSearch | How many videos to take from each search, top results first. Videos without captions aren't charged, so you can end up with fewer transcripts than this. | integer |
retries | Retries for temporary rate limits and YouTube server errors. Backoff is automatic. | integer |
languagePreferences | BCP 47 language codes in priority order, for example en, es, fr, or pt-BR. The first available preference is used. If none match, the actor falls back to another available transcript. | array |
maxConcurrency | Number of videos processed at once. Keep this low to reduce YouTube throttling and compute cost. | integer |
requestTimeoutSecs | Maximum time for all transcript requests for one video. | integer |
What you get
A structured dataset — each result includes fields like:
okvideoIdtitledetectedLanguagesegmentCounttexturlsearchKeyworderrorCodeExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
2 ready-to-run use cases
YouTube Transcript in Spanish, English as Fallback
Spanish subtitles first, English when there is no Spanish track, as text, SRT and VTT. Each row says which language it actually came back with.
Download YouTube Transcript as Text, SRT and VTT
Paste links and get the transcript as plain text, timed segments, SRT and VTT. No API key, no login. Videos with captions off return an error row.
Ready-made automation using this tool
A finished workflow you can import into n8n and run — this tool does the data-gathering inside it. Free, and yours to change.
Get a short summary whenever a channel uploads
Watches the YouTube channels you pick. When one uploads, it reads the transcript, writes a few lines on what the video actually covers, and posts that to Slack, Notion or a spreadsheet — so you can decide whether to watch it.
Related tools in YouTube & Creator Tools
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
YouTube Trending Scraper
Get the most-viewed YouTube videos for any topic, no login or key. Rows carry views, titles, channels, duration, thumbnails. $0.40 per 1,000 videos.
YouTube Channel Email Scraper
Find the business emails creators publish in their YouTube channel description, plus their linked site's contact pages. $1.50 per 1,000 channels.
YouTube Scraper
Search YouTube or scrape a channel: title, channel, views, publish date, length and thumbnail. No API key or quota. $0.135 per 1,000 videos.
YouTube Channel Monitor — New Upload Tracker
Watch YouTube channels and get only their new uploads: title, URL, publish date, views, thumbnail. $0.01 per new video.
YouTube Video & Audio Downloader
Download YouTube videos as MP4 up to 8K, audio as MP3 or subtitles as .srt. No login or API key. You pay per megabyte delivered.
YouTube Video Uploader
Upload videos to your YouTube channel from a URL with OAuth. Set title, tags, category, thumbnail, privacy and publish time. $0.05 per upload.
Where this tool sits
- Categories
- YouTube & Creator Tools
- Platforms
- YouTube
YouTube Transcript Scraper: captions as text, timed segments, SRT and VTT
Paste watch, Shorts, live, embed or youtu.be links or bare 11 character ids, or just type a search, and each video comes back as one row holding the full plain text, the timed segments, a ready-to-save SRT and a ready-to-save WebVTT. No API key, no cookies, no login.
The honest limit: it reads caption tracks the video already has. It does not listen to the audio, so a video nobody captioned and that YouTube never auto-captioned comes back as NO_TRANSCRIPT, and no setting changes that.
| Input | YouTube links, video ids, or search keywords |
| Output | One row per video, with text, segments, SRT and VTT |
| Ceiling | 400 videos per run |
| Account needed | None from you |
| Price | $0.80 per 1,000 transcripts, flat on every plan |
📝 What YouTube Transcript Scraper does
For each video it finds the caption tracks, picks one using languagePreferences in order, and pulls the cues. An exact match wins, then a base-language match, so pt-BR falls back to pt. If none of your preferences exist it takes another available track rather than failing the video, and detectedLanguage tells you what it actually used.
Manual captions are preferred over auto-generated ones when both exist. isAutoGenerated says which you got, and availableLanguages lists everything the video had, so you can re-run for a different one.
Type something into searchKeywords instead and it searches YouTube, takes the top maxVideosPerSearch videos from each search, and handles them like pasted links. Shorts, channels and playlists are left out of the results. Each row it finds carries searchKeyword and searchRank.
One charge covers the whole row: the plain text, the segments, the SRT, the VTT, the language list and the metadata. There is no per-format or per-language extra. A video that turns up in more than one place, links or searches, is processed once.
📥 What you give it
{
"videoUrls": [
"https://www.youtube.com/watch?v=M7lc1UVf-VE",
"https://youtu.be/dQw4w9WgXcQ",
"aqz-KE-bpKQ"
],
"languagePreferences": ["fr-CA", "fr", "en"]
}
Or search instead of pasting:
{
"searchKeywords": ["sourdough for beginners", "no knead bread recipe"],
"maxVideosPerSearch": 10
}
| Field | Default | What it is |
|---|---|---|
videoUrls | [] | Watch, Shorts, live, embed and youtu.be links, or bare ids. Up to 200. |
videoIds | [] | A second list for raw ids, handy when your pipeline stores them separately. Up to 200. |
searchKeywords | [] | Searches to run, one per line. Up to 20. Works on its own or next to links. |
maxVideosPerSearch | 10 | How many top results to take from each search, 1 to 100. |
languagePreferences | ["en"] | BCP 47 codes in priority order, such as en, es, pt-BR. Up to 20. |
maxConcurrency | 2 | Videos handled at once, 1 to 10. Low on purpose: it keeps the run steady and cheap. |
retries | 2 | Retries for rate limits and server errors, 0 to 5. Backoff is automatic. |
requestTimeoutSecs | 45 | Total time allowed per video, 10 to 180 seconds. |
proxyConfiguration | off | Off by default, which is the right setting almost always. Turn it on only if a run is being rate limited. |
Run it with empty input and you get one labelled sample row, uncharged, so you can see the shape first.
📤 What you get back
A real row from a real run. text, segments, srt and vtt are cut short here, because the full row is about 20 KB of the same transcript in four shapes:
{
"ok": true,
"_sample": false,
"_diagnostic": false,
"videoId": "M7lc1UVf-VE",
"url": "https://www.youtube.com/watch?v=M7lc1UVf-VE",
"title": "YouTube Developers Live: Embedded Web Player Customization",
"author": "Google for Developers",
"channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
"viewCount": 1656845,
"durationSeconds": 1344,
"detectedLanguage": "en",
"requestedLanguage": "en",
"isAutoGenerated": false,
"segmentCount": 466,
"text": "JEFF POSNICK: Hey, everybody. Welcome to this week's show of YouTube Developers Live. ...",
"segments": [
{ "text": "JEFF POSNICK: Hey, everybody.", "start": 10.349, "duration": 1, "end": 11.349 },
{ "text": "Welcome to this week's show of YouTube Developers Live.", "start": 11.349, "duration": 2.681, "end": 14.03 }
],
"srt": "1\n00:00:10,349 --> 00:00:11,349\nJEFF POSNICK: Hey, everybody. ...",
"vtt": "WEBVTT\n\n00:00:10.349 --> 00:00:11.349\nJEFF POSNICK: Hey, everybody. ...",
"availableLanguages": [
{ "languageCode": "en", "languageName": "English", "isAutoGenerated": false },
{ "languageCode": "en", "languageName": "English (auto-generated)", "isAutoGenerated": true }
]
}
| Field | What it is |
|---|---|
text | The whole transcript as one string, cues joined. |
segments | Every cue with start, duration and end in seconds, for anything timestamp driven. |
srt, vtt | The same cues formatted as subtitle files. Save the string straight to .srt or .vtt. |
detectedLanguage, requestedLanguage | What you got, and the first thing you asked for. Compare them to spot a fallback. |
isAutoGenerated | true when the track is machine-made, which is where the punctuation and names get loose. |
availableLanguages | Every track the video carried, so a second run can fetch a different one. |
title, author, channelId, viewCount, thumbnailUrl | Video metadata. Any of them can be null when YouTube did not return it. |
searchKeyword, searchRank | Which search found the video and where it ranked. Only on rows that came from a search. |
🧾 Reading the output
Three kinds of row can land in your dataset, and the flags are how you tell them apart.
| Row | How to spot it | Billed |
|---|---|---|
| A transcript | ok: true and _sample: false | yes |
| The sample row | _sample: true, videoId SAMPLE00000 | no |
| A diagnostic | ok: false, _diagnostic: true, an errorCode | no |
The Overview table has no _sample column, so the free sample row reads there as a perfectly good transcript. Filter on _sample == false before counting anything.
The error codes are the useful part of a diagnostic row, and each carries a hint:
errorCode | What happened |
|---|---|
NO_TRANSCRIPT | The video has no caption track in any language. |
VIDEO_UNAVAILABLE | Private, removed, or the id does not exist. |
LOGIN_REQUIRED | Age-gated or members-only, so a signed-out reader cannot open it. |
INVALID_VIDEO | The string you passed is not a YouTube link or an 11 character id. |
RATE_LIMITED | YouTube pushed back on that video. Re-running usually clears it. |
NO_SEARCH_RESULTS | A search found no videos. Try fewer or different words. |
SEARCH_FAILED | A search could not be run. Try again in a few minutes. |
EXTRACTION_FAILED | Tracks were found but no cues came back. |
TIME_LIMIT | The run got close to its time limit and stopped early. Every transcript delivered before that is in your dataset; give the run more time, or ask for fewer videos, to get the rest. If none came back at all, the run is marked as failed. |
RUN_ERROR | The run itself failed, written as one row so the reason survives. |
A batch where every video fails still finishes as a successful run, with diagnostics and nothing else. Count ok: true rows rather than trusting the run status.
▶️ How to run it
1. Open YouTube Transcript Scraper and click Try for free. 2. Press Start with the input empty to see the free sample row. 3. Paste links or ids into Video URLs or IDs, or type what you want into Search keywords. 4. Set Preferred transcript languages if English is not what you want. 5. Download the dataset as JSON, or pull srt out of a row and save it as a subtitle file.
💰 How much does it cost?
$0.80 per 1,000 transcripts, the same on every Apify plan.
You pay per transcript returned. The sample row, diagnostic rows and duplicate ids are never billed, so a batch of 100 videos where 12 have no captions bills 88 transcripts, not 100.
💡 What people use it for
- Turning a talk or interview into text you can search, quote and paste into notes.
- Feeding transcripts to a model for summaries, without paying a speech-to-text bill.
- Making
.srtfiles for re-uploads, or as the starting point for a translation pass. - Finding the exact moment a phrase was said, using
segmentsto jump to the second.
🚧 What it does not do
- No speech to text. Published caption tracks only, auto-generated ones included. Nothing
captioned means nothing to return.
- No translation. It fetches tracks that exist. If the video has no French track, asking for
French gets you another language, not a translation.
- One video per entry. Channel and playlist links are not expanded here. There is a bulk actor
below for that.
durationSecondscan be the transcript's length, not the video's, when YouTube returned no
metadata for that video. Sanity check it against the last segment's end if it matters.
- Metadata can be
null. Title, author, view count and thumbnail come from YouTube's own
response and are sometimes absent, while the transcript itself is fine.
- Auto-generated tracks have no reliable punctuation or speaker names, and get proper nouns
wrong. isAutoGenerated is how you know which you are reading.
- Rows are large, roughly 18 to 24 KB each, because text, segments, SRT and VTT hold the same
words four ways. A 400 video run is a chunky dataset.
- Search takes YouTube's own top results. There is no filter for upload date, length or views, and
a video without captions still uses up one of the places you asked for.
- 400 videos per run in total, links and search results together.
🧭 Which YouTube scraper do you need?
| If you want | Use |
|---|---|
| Transcripts for videos you already have links for | This one |
| Transcripts for a whole channel or playlist in one run | YouTube Transcript Bulk Scraper |
| The video or its audio as a file | YouTube Downloader |
| The comments under the video | YouTube Comments Scraper |
| Videos to run this on, by keyword or channel | YouTube Scraper |
❓ Questions people ask
Do I need a YouTube Data API key? No. No key, no cookies, no OAuth, no quota.
What if the video has no captions? You get an uncharged NO_TRANSCRIPT row and the batch carries on. It does not transcribe the audio.
Which language do I get? The first one in languagePreferences that exists, an exact match before a base-language one. Otherwise another available track, named in detectedLanguage.
Can I get the SRT file directly? The srt field is the file's contents. Write the string to a .srt and it plays.
Why is one video missing from my results? Look for its diagnostic row. LOGIN_REQUIRED and VIDEO_UNAVAILABLE are permanent for a signed-out reader, RATE_LIMITED is worth retrying.
Is scraping YouTube legal? This reads publicly available captions. What you then do with somebody else's words is your call, and copyright still applies. Apify's write-up on the legality of web scraping is a good starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Include the video link and the run ID, and the errorCode on the diagnostic row if you got one.