YouTube Video Subtitles Scraper — Chapters, SRT & VTT Export
Pricing
from $5.99 / 1,000 results
YouTube Video Subtitles Scraper — Chapters, SRT & VTT Export
Extract video subtitles effortlessly with the YouTube Video Subtitles Scraper. Retrieve full transcripts, timestamps, and multiple language options from any YouTube video. Ideal for content analysis, research, accessibility, and translation projects. Fast, accurate, and easy to use at scale.
Pricing
from $5.99 / 1,000 results
Rating
0.0
(0)
Developer
Scrapier
Maintained by CommunityActor stats
0
Bookmarked
5
Total users
0
Monthly active users
4 days ago
Last modified
Categories
Share
YouTube Video Subtitles Scraper — Chapters, SRT & VTT Export
Paste in YouTube video links and get back the timestamped transcript for every video — split into the creator's own real chapters, plus ready-to-paste SRT, VTT and plain-text exports as string fields, never a downloaded file. Every response is structured JSON, ready to pass directly to an LLM, index into a vector store, or feed a monitoring pipeline. No YouTube login or API key is required — just the video links. Point it at a handful of URLs or a few hundred, and start building subtitle files, show notes, or a transcript-searchable archive today.
What is YouTube Video Subtitles Scraper — Chapters, SRT & VTT Export?
YouTube Video Subtitles Scraper takes a list of YouTube video links and returns, for each video, full metadata, the timestamped transcript, and — when the creator published real chapter markers — the same transcript sliced into chapters[], one entry per chapter. It never invents a chapter: videos without real chapter markers honestly report hasChapters: false and chapters: null instead of a fabricated single chapter. Alongside the base transcript, it can re-encode the captions as srtText, vttText and plainText — plain string fields on the row, ready to paste straight into a subtitle file, no file download or key-value-store artifact involved. No YouTube account, cookies, or login are required — the Actor extracts everything from what YouTube exposes on the public watch page.
- 🎬 Full video metadata — title, channel, duration, view/like/comment counts, publish date, description, tags
- 📝 Timestamped transcript as a
transcript[]array (start,dur,text) - 🧩 Real, creator-defined chapter segmentation via
chapters[]— never AI-guessed - 📄 SRT, VTT and plain-text exports as data fields (
srtText,vttText,plainText) - 🌍 Preferred caption language with an automatic fallback ladder (manual caption → auto-generated English → any auto-generated caption)
- ⚙️ Configurable concurrency (
maxWorkers, 1–10 videos in parallel)
What data can you get with YouTube Video Subtitles Scraper?
The Actor extracts five kinds of data for every video link you submit:
| Result Type | Extracted Fields | Primary Use Case |
|---|---|---|
| Video metadata | videoId, type, url, title, channel_name, channelId, channelUrl, length, views, publishedAt, likeCount, commentCount, description, tags | Video cataloging, content audits, channel research |
| Timestamped transcript | transcript[] (start, dur, text) | Search indexing, custom players, quote sourcing |
| Real, creator-defined chapters | hasChapters, chapterSource, chapters[] (chapterIndex, title, startSeconds, endSeconds, chapterText, wordCount, deepLinkUrl) | Chapter-level summaries, deep-linking to a moment, study notes |
| Ready-to-paste text exports | srtText, vttText, plainText | Subtitle files, blog repurposing, LLM context windows |
| Run status | message, success, status, scrapedAt | Pipeline monitoring, retry logic, QA |
🧩 Real, Creator-Defined Chapters
Most transcript tools either ignore chapters entirely or fake them by guessing topic boundaries from the text. This Actor reads the actual chapter markers the video's creator set when they published or edited the video, then slices the transcript at those exact boundaries — no inference, no hallucinated titles. Each entry in chapters[] carries its own text slice (chapterText), word count, and a deep link that jumps straight to that moment (deepLinkUrl). Untitled or placeholder chapters (like "Chapter 3") can be kept as their own entry with title: null, or folded into the previous chapter, via includeUntitledChapters. Videos with no real chapters report hasChapters: false and chapters: null — never a fabricated single chapter.
{"hasChapters": true,"chapterSource": "creator_defined","chapters": [{"chapterIndex": 0,"title": "Intro","startSeconds": 0,"endSeconds": 42.5,"chapterText": "Welcome back to the channel, today we're breaking down...","wordCount": 138,"deepLinkUrl": "https://youtu.be/dQw4w9WgXcQ?t=0"},{"chapterIndex": 1,"title": null,"startSeconds": 42.5,"endSeconds": 96.0,"chapterText": "So the first thing you'll notice is...","wordCount": 54,"deepLinkUrl": "https://youtu.be/dQw4w9WgXcQ?t=42"}]}
📄 Multi-Format Text Exports
outputFormats controls three fields — srtText (standard .srt grammar), vttText (WebVTT) and plainText (words only, no timestamps). Each is a plain string sitting on the same row as the metadata and chapters, so there's no separate download link or ZIP to fetch. Copy srtText straight into a .srt file for a video editor, drop plainText into a CMS field or an LLM prompt, or embed vttText directly in an HTML5 <track> tag.
100:00:00,000 --> 00:00:03,240Welcome back to the channel, today we're200:00:03,240 --> 00:00:06,010breaking down exactly how this works.
How does YouTube Video Subtitles Scraper differ from the official YouTube Data API?
The official YouTube Data API v3 exposes caption tracks through captions.list and captions.download, but captions.download requires OAuth 2.0 authorization and the authenticated user must have edit permission on the video — in practice, the caller must be the video's own owner/channel. As of the documentation checked on 2026-08-15, it cannot be used to pull captions for arbitrary third-party public videos (Google for Developers, captions.download).
| Feature | YouTube Data API v3 | YouTube Video Subtitles Scraper |
|---|---|---|
| Caption access for third-party videos | ❌ requires OAuth + edit permission on that video | ✅ works on any public video link |
| Real chapter data | Not returned by the captions endpoints | ✅ chapters[], sourced from the video's own metadata |
| Export formats | Original/tfmt-specified caption format, own videos only | srtText, vttText, plainText, transcript on every row |
| Setup | Google Cloud project, OAuth consent screen, API quota | Paste video links and run — no Google account |
| Output shape | One caption track per authorized request | Normalized JSON row per video, batched in one run |
Use the official API when you own the videos and need to manage or upload captions inside your own Google Cloud project. Use this Actor when you need transcripts, chapters, and export-ready text from videos you don't own — including anyone's public uploads.
What is the difference between AI-generated video summaries and real chapter markers?
AI-generated video summaries invent chapter breaks by analyzing the transcript after the fact — a language model guesses where one topic ends and another begins. Real chapter markers are timestamps the video's own creator set in YouTube Studio when they published or edited the video, matching the exact structure they intended. That distinction matters more as AI summarizer tools spread: a guessed boundary can split a sentence mid-thought or mislabel a segment, which is a real problem if you're citing a specific moment, building study notes, or generating navigation a viewer will actually use. YouTube Video Subtitles Scraper only returns chapters that exist in the video's own published metadata (chapterSource: "creator_defined") — it never runs its own topic-detection pass, and it reports hasChapters: false rather than guessing when a video has none.
How to scrape YouTube with YouTube Video Subtitles Scraper?
- Open the Actor's page on the Apify Store and click Try for free (or Run, if you already have it).
- Paste one or more YouTube video links into
videoLinks— one per line. Watch links,youtu.beshort links, and Shorts links are all accepted. - Set the real controls you need:
captionLanguagefor your preferred transcript language,splitByChaptersandincludeUntitledChaptersfor chapter behavior,outputFormatsfor which export strings to generate. - Click Start to launch the run.
- Once it finishes, open the Dataset tab and export the results as JSON, CSV, Excel, or another supported format — or pull them programmatically via the Apify API.
How to run multiple videos in one job
Add every video link to the videoLinks array — there's no separate "batch mode" to enable. Each video is processed independently, and its row is written to the dataset the moment it's ready, regardless of input order. maxWorkers (1–10, default 4) controls how many videos run in parallel; raising it processes more videos concurrently instead of one at a time.
⬇️ Input
The Actor accepts a list of YouTube video links plus optional controls for caption language, chapter handling, export formats, and concurrency. No parameter is marked required in the input schema, but at least one usable video link (via videoLinks or the legacy startUrls) is required at run time — a run with none fails immediately with a clear message.
| Parameter | Required | Type | Description | Example Value |
|---|---|---|---|---|
videoLinks | No | array | One line per video. Accepts full watch links (https://www.youtube.com/watch?v=VIDEO_ID), short links (https://youtu.be/VIDEO_ID) and Shorts links. Each video is processed on its own and its row is written to the output table the moment it is ready. | ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"] |
captionLanguage | No | string | Language code to prefer for the transcript (examples: en English, es Spanish, fr French). When the exact language is not available, the actor falls back to any manual caption, then to auto-generated English, then to any auto-generated caption — the real source is always reported in message. | "en" |
maxWorkers | No | integer | How many videos are processed in parallel (1–10). Example: 4 processes up to 4 videos at once instead of one at a time. Rows are written to the output table as soon as each video finishes, regardless of input order. Default: 4. Minimum: 1. Maximum: 10. | 4 |
splitByChapters | No | boolean | When on, every video with real chapter markers gets a chapters[] list — one entry per chapter, each with its own text slice, word count and timestamped link. Videos without chapters report hasChapters: false and chapters: null, never a fabricated single chapter. | true |
includeUntitledChapters | No | boolean | When on, chapters that have no real title (or only a placeholder like "Chapter 3") are kept as their own entry with title: null. When off, such a chapter's text is folded into the chapter right before it, so every chapter in the output has a real title. Default: true. | true |
outputFormats | No | array | Pick which formats to generate: srt fills srtText (standard .srt grammar), vtt fills vttText (WebVTT), plainText fills plainText (the words with no timestamps), timestampedJson keeps the existing transcript array populated. Deselecting a format simply leaves that field null on the row — nothing is ever written to a file or storage. Enum: srt, vtt, plainText, timestampedJson. | ["srt", "vtt", "plainText", "timestampedJson"] |
startUrls | No | array | Backward-compatible alias of videoLinks above. If both are filled, videoLinks is used and any extra items here are appended. | ["https://youtu.be/dQw4w9WgXcQ"] |
language | No | string | Backward-compatible alias of captionLanguage above. | "en" |
proxyConfiguration | No | object | Optional. Leave the default for normal use, or pick your own Apify Proxy option for larger runs. | {"useApifyProxy": true} |
Example JSON input
{"videoLinks": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ","https://youtu.be/9bZkp7q19f0","https://www.youtube.com/watch?v=jNQXAC9IVRw"],"captionLanguage": "en","maxWorkers": 4,"splitByChapters": true,"includeUntitledChapters": true,"outputFormats": ["srt", "vtt", "plainText", "timestampedJson"],"proxyConfiguration": {"useApifyProxy": true}}
Common pitfall: the Actor only recognizes watch, youtu.be, and Shorts URLs — a channel URL, playlist URL, or search-results link is rejected immediately with status: "invalid_url" rather than silently skipped or crawled for videos. Submit individual video links, not a channel or playlist to expand.
⚠️ One real quirk worth knowing: the transcript field is always populated whenever a caption track is found, regardless of whether timestampedJson is selected in outputFormats. Only srtText, vttText, and plainText are actually gated by that selection — deselecting timestampedJson does not clear transcript.
⬆️ Output
Every run writes one normalized JSON row per video link to the Apify dataset, with the same 25 keys on every row regardless of whether that video succeeded, failed, or had no chapters — fields that don't apply are simply null rather than omitted. Rows are pushed as soon as each video finishes, not batched at the end. Export the dataset as JSON, CSV, Excel, XML, or RSS from the Apify Console, or pull it via the API.
Scraped results
[{"videoId": "dQw4w9WgXcQ","type": "video","url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ","title": "How This Actually Works: A Full Walkthrough","channel_name": "Example Channel","length": "12:34","views": 1284933,"publishedAt": "2025-03-11T00:00:00+00:00","likeCount": 45210,"commentCount": 1832,"hasChapters": true,"chapters": [{"chapterIndex": 0,"title": "Intro","startSeconds": 0,"endSeconds": 42.5,"chapterText": "Welcome back to the channel, today we're breaking down...","wordCount": 138,"deepLinkUrl": "https://youtu.be/dQw4w9WgXcQ?t=0"},{"chapterIndex": 1,"title": "Setting Up","startSeconds": 42.5,"endSeconds": 210.0,"chapterText": "So the first thing you'll notice is...","wordCount": 402,"deepLinkUrl": "https://youtu.be/dQw4w9WgXcQ?t=42"}],"chapterSource": "creator_defined","srtText": "1\n00:00:00,000 --> 00:00:03,240\nWelcome back to the channel, today we're\n\n2\n00:00:03,240 --> 00:00:06,010\nbreaking down exactly how this works.\n","vttText": "WEBVTT\n\n00:00:00.000 --> 00:00:03.240\nWelcome back to the channel, today we're\n\n00:00:03.240 --> 00:00:06.010\nbreaking down exactly how this works.\n","plainText": "Welcome back to the channel, today we're breaking down exactly how this works.","transcript": [{"start": "0.000", "dur": "3.240", "text": "Welcome back to the channel, today we're"},{"start": "3.240", "dur": "2.770", "text": "breaking down exactly how this works."}],"description": "In this video we walk through...","tags": ["tutorial", "walkthrough", "how-to"],"channelId": "UCexample1234567890","channelUrl": "https://www.youtube.com/channel/UCexample1234567890","message": "Transcript loaded (manual, language: en).","success": true,"status": "ok","scrapedAt": "2026-08-15T10:04:12.531000+00:00"},{"videoId": "9bZkp7q19f0","type": "video","url": "https://youtu.be/9bZkp7q19f0","title": "A Short Clip With No Chapters","channel_name": "Another Channel","length": "3:12","views": 88213,"publishedAt": "2024-11-02T00:00:00+00:00","likeCount": 2104,"commentCount": 96,"hasChapters": false,"chapters": null,"chapterSource": null,"srtText": "1\n00:00:00,000 --> 00:00:02,500\nQuick one today.\n","vttText": "WEBVTT\n\n00:00:00.000 --> 00:00:02.500\nQuick one today.\n","plainText": "Quick one today.","transcript": [{"start": "0.000", "dur": "2.500", "text": "Quick one today."}],"description": "A short clip.","tags": null,"channelId": "UCexample0987654321","channelUrl": "https://www.youtube.com/channel/UCexample0987654321","message": "Transcript loaded (auto-generated, language: en).","success": true,"status": "ok","scrapedAt": "2026-08-15T10:04:15.902000+00:00"},{"videoId": "jNQXAC9IVRw","type": "video","url": "https://www.youtube.com/watch?v=jNQXAC9IVRw","title": "Unknown Title","channel_name": "N/A","length": "0:00","views": null,"transcript": [],"message": "No caption track is available for this video in the requested language.","success": false,"status": "unavailable","type": "video","description": null,"tags": null,"channelId": null,"channelUrl": null,"publishedAt": null,"likeCount": null,"commentCount": null,"hasChapters": false,"chapters": null,"chapterSource": null,"srtText": null,"vttText": null,"plainText": null,"scrapedAt": "2026-08-15T10:04:18.114000+00:00"}]
How can I use the data extracted with YouTube Video Subtitles Scraper?
- 🎬 Content creators, podcasters and repurposing agencies: turn
chapters[]andplainTextinto show notes, blog posts and social clips without manually re-typing a single word. - 🤖 AI engineers and LLM developers: feed
transcriptorchapterTextinto a RAG pipeline so an agent can answer questions grounded in a video's actual spoken content, chapter by chapter. - ♿ Localization and accessibility teams: drop
srtTextorvttTextdirectly into a video's subtitle track to ship captions without running your own transcription pipeline. - 📊 Content researchers and analysts: compare
chapterTextacross a set of videos to see how competitors structure and cover a topic.
How do you monitor caption and chapter changes over time?
Captions and chapters aren't fixed the moment a video goes live — creators frequently edit chapter markers after publishing, replace auto-generated captions with manually corrected ones, or add captions to a video that previously had none. Monitoring means re-running the same set of videoLinks on a schedule and diffing the new dataset against the previous run. The fields worth diffing are status (did it move from "unavailable" or "error" to "ok"?), hasChapters (did real chapters just get added?), the title and count of entries inside chapters[], and whether srtText/vttText went from null to populated. A simple workflow: schedule a run across a fixed list of video links → compare each video's status and hasChapters against last run's dataset → alert when a video that previously had no usable transcript now returns status: "ok", or when its chapter count changes. Set this up with an Apify Schedule on the Actor, and export or pull each run's dataset to do the comparison.
Integrate YouTube Video Subtitles Scraper and automate your workflow
YouTube Video Subtitles Scraper works with any language or tool that can send an HTTP request.
REST API with Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_API_TOKEN>")# Actor ID is on the Actor's "API" tab in the Apify Consolerun = client.actor("<AUTHOR>/youtube-video-subtitles-scraper-chapters-srt-and-vtt-export").call(run_input={"videoLinks": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],"outputFormats": ["srt", "plainText"],})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["title"], "->", item["status"])
MCP for AI agents
The Actor is reachable through Apify's own Actors MCP Server, which exposes any Apify Actor — including this one — as a callable tool for MCP-compatible clients. Connect via the hosted endpoint https://mcp.apify.com (OAuth, or an Authorization: Bearer <APIFY_TOKEN> header) or run it locally with npx @apify/actors-mcp-server and an APIFY_TOKEN environment variable, as documented at docs.apify.com/integrations/mcp (checked 2026-08-15). An agent asks for a video's transcript, the MCP server runs this Actor, and the agent gets back structured JSON — chapters, exports, and metadata included — to ground its answer.
Scheduled monitoring and delivery
Use Apify Schedules in the Console to re-run this Actor against a fixed videoLinks list on a cron interval, and configure a webhook to fire on each run's completion so downstream systems pick up the new dataset automatically.
⚖️ Is it legal to scrape YouTube video transcripts?
Yes — this Actor extracts publicly viewable video metadata and caption text, the same information any visitor sees on the video's watch page; nothing behind a login or paywall is accessed. Because the output is a video's title, metadata and transcript rather than the personal data of private individuals, the relevant framework is YouTube's own Terms of Service and copyright, not GDPR or CCPA. Automated access is subject to YouTube's Terms of Service, and the transcript text itself is the creator's copyrighted work — reproducing or redistributing full transcripts commercially can raise separate copyright questions beyond simple data scraping. Scraping a handful of videos for internal monitoring or research carries a different risk profile than bulk-scraping content to train or fine-tune a model. Consult your legal team for commercial use cases involving bulk data storage or redistribution.
❓ Frequently asked questions
Which caption languages does the Actor support?
Any language code YouTube publishes a caption track for. Set captionLanguage (e.g. en, es, fr) to your preferred language; if that exact language isn't available, the Actor falls back to any manual caption, then auto-generated English, then any auto-generated caption — and reports which one it actually used in message (e.g. "Transcript loaded (manual, language: en).").
Can I choose which export formats I get back?
Yes. outputFormats accepts any combination of srt, vtt, plainText, and timestampedJson. Deselecting a format leaves that field null on the row rather than generating it — except transcript, which is always populated when a caption track is found regardless of whether timestampedJson is selected (see the note in the Input section).
How does the Actor handle YouTube's anti-bot and rate-limit measures?
It watches for blocking signals in errors — HTTP 429/403, rate-limit messages, "sign in" or bot-check pages, and unavailable-video responses — and automatically escalates through Apify's proxy network on the next attempt, retrying up to 3 times per video before giving up and returning status: "error". This escalation can kick in even if proxyConfiguration.useApifyProxy was left off, since the Actor requests its own proxy route once it detects it's being blocked.
Does the Actor extract real chapter markers, not AI-guessed ones?
Yes. When splitByChapters is on, chapters[] is built only from the chapter timestamps the video's own creator published (chapterSource: "creator_defined") — the Actor never runs its own topic-detection pass. Videos with no real chapter markers report hasChapters: false and chapters: null.
How many videos can I process in one run?
There's no documented cap on the number of items in videoLinks — add as many as your run's time and memory allow. maxWorkers controls how many are processed in parallel at once: 1 to 10, default 4.
Is the transcript field affected by the outputFormats selection?
No — this is a known quirk. transcript is populated whenever a caption track is found, regardless of whether timestampedJson is included in outputFormats. Only srtText, vttText, and plainText are actually gated by that setting.
How do I monitor a video's captions or chapters for changes over time?
Schedule a run of the same videoLinks on a recurring basis using an Apify Schedule, then diff each new dataset against the previous one on status, hasChapters, and the contents of chapters[] — alert when a video's caption availability or chapter structure changes.
Does the Actor work with Claude, ChatGPT, and AI agent frameworks?
Yes. It's reachable through Apify's Actors MCP Server (https://mcp.apify.com or npx @apify/actors-mcp-server) for MCP-compatible clients, and as a plain HTTP endpoint via the Apify API for any agent framework that can call a REST API and parse JSON.
Can I use the Actor without managing proxies or a YouTube account?
Yes. No YouTube login, cookies, or API key are required — the Actor extracts everything from the public watch page. Proxy handling is automatic: it starts on the connection you configure (or a direct connection by default) and escalates through Apify's proxy network on its own if it detects blocking.
💬 Your feedback
Found a bug, or need a field this Actor doesn't return yet? Open an issue from the Issues tab on this Actor's Apify Store page, or message Scrapier through the Console — reports like these directly shape what gets fixed and added next.