ChimeraMiND Data
Home / Guides / YouTube Transcript Scraper
Video & AI data

YouTube transcript API: captions with timestamps, in bulk

A YouTube transcript API without an API key. Pull the full transcript and timestamped caption segments of any public video or a channel's latest uploads, with language fallback and a completeness check, ready for search, summaries and RAG.

Transcripts are the most useful part of a YouTube video for anything that isn't watching it: summarising a talk, searching a course library, quoting a podcast, or feeding an AI model that answers questions about a channel. YouTube shows them one video at a time behind a menu, and the official Data API does not let third-party apps download caption text without the channel owner's authorisation. This guide shows how to get the full transcript of many videos at once — plain text plus timestamped segments — through a simple JSON API, for $4 per 1,000 videos.

What you get

One row per video: the video and channel identifiers, title, duration, the caption track that was used, every language the video offers, the whole transcript as one text string and — unless you turn it off — a segments array of {start, dur, text} objects. A real row from a recorded run, trimmed:

Archived example · 7 days old. This is a snapshot, not current data.run 9M6gHlUDOofZDuobK · 2026-10-11
{
  "videoId": "dQw4w9WgXcQ",
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
  "channelName": "Rick Astley",
  "channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
  "durationSeconds": 213,
  "publishDate": "2009-10-25T06:57:33.000Z",
  "viewCount": 1825545748,
  "language": "en",
  "languageName": "English",
  "isAutoGenerated": false,
  "availableLanguages": [
    "en",
    "en",
    "de-DE"
  ],
  "text": "[♪♪♪] ♪ We're no strangers to love ♪ ♪ You know the rules and so do I ♪ ♪ A full commitment's what I'm thinking of ♪ ♪ You wouldn't get this from any other guy ♪ ♪ I just wanna tell you how I'm feeling ♪ ♪ Gotta make you understand ♪ ♪ Never gonna give you up ♪ ♪ Never gonna l…",
  "segments": [
    {
      "start": 1.36,
      "dur": 1.68,
      "text": "[♪♪♪]"
    },
    {
      "start": 18.64,
      "dur": 3.24,
      "text": "♪ We're no strangers to love ♪"
    },
    {
      "start": 22.64,
      "dur": 4.32,
      "text": "♪ You know the rules and so do I ♪"
    }
  ],
  "segmentCount": 61,
  "transcriptComplete": true,
  "transcriptCoverage": 0.992,
  "scrapedAt": "2026-10-11T15:34:54.606Z"
}
Field Meaning
videoId, url, title The video
channelName, channelId Who uploaded it
durationSeconds, publishDate Length, and the publish date in ISO 8601 UTC (null when YouTube does not report it)
language, languageName, isAutoGenerated Which caption track was extracted, and whether YouTube generated it automatically
availableLanguages Every caption language the video offers
text The whole transcript as one plain-text string
segments, segmentCount Timestamped pieces with start time and duration in seconds
transcriptComplete, transcriptCoverage Whether the captions reach the end of the video, and how much of it they cover
viewCount, scrapedAt View count at extraction time and the extraction timestamp
error Why a video had no transcript, for example no captions

Which caption track you get

Set a preferred language (two-letter code, en by default). If the video has captions in that language, you get them. If not, the tool falls back in this order: the first manually created track in any language, then the first auto-generated track (when Include auto-generated captions is on, the default), then any track at all. The row always says what you received through language and isAutoGenerated, so a pipeline can filter out auto-captions or other languages.

Check that the transcript is complete

YouTube's caption track sometimes ends before the video does, with silent endings, music or auto-captions that stop early. transcriptCoverage is the end time of the last caption segment divided by the video's duration (0 to 1), and transcriptComplete is false when that coverage falls below 90 %. Treat false as "captions are partial", not as a failed run. Filter on it before you summarise or index a video.

Step-by-step

  1. Paste videos into Video URLs: full watch?v= links, Shorts links, youtu.be links or bare 11-character IDs, one per line.
  2. Or set Channel URL (for example https://www.youtube.com/@channelname) and Max videos to take the channel's latest uploads. A channel URL overrides the video list.
  3. Pick your Language and decide whether to include auto-generated captions and segments. Turn segments off if you only need the text; the dataset becomes much smaller.
  4. Leave Proxy mode on auto. Requests go out directly and switch to a residential proxy only if YouTube starts rate-limiting.
  5. Click Start and export as JSON, CSV or Excel, or read the rows through the API.

Run YouTube Transcript Scraper on Apify →

Call it from code

import json
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"]) run = client.actor("webdatatools/youtube-transcript-scraper").call(run_input=json.loads("{\n "videoUrls": [\n "https://www.youtube.com/watch?v=dQw4w9WgXcQ\"\n ],\n "maxVideos": 10,\n "language": "en"\n}"))

for item in client.dataset(run["defaultDatasetId"]).iterate_items(): print(item)

import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN }); const run = await client.actor('webdatatools/youtube-transcript-scraper').call({ "videoUrls": [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ" ], "maxVideos": 10, "language": "en" }); const { items } = await client.dataset(run.defaultDatasetId).listItems(); console.log(items);

curl -X POST "https://api.apify.com/v2/acts/webdatatools~youtube-transcript-scraper/run-sync-get-dataset-items" 
-H "Authorization: Bearer $APIFY_TOKEN"
-H "Content-Type: application/json"
-d '{"videoUrls":["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],"maxVideos":10,"language":"en"}'

Use it in n8n or Make

Call the API from a workflow tool with the HTTP Request node in n8n: method POST, URL https://api.apify.com/v2/acts/webdatatools~youtube-transcript-scraper/run-sync-get-dataset-items, a header Authorization with the value Bearer YOUR_APIFY_TOKEN, and a JSON body. The response is one item per video. In Make, use HTTP > Make a request with the same method, URL and header, body type Raw with JSON content, and Parse response on, then iterate over the array.

Synchronous calls wait for the run to finish, so use them for a handful of videos. For a whole channel, start the run asynchronously and read the dataset when it completes.

Body example:

{
    "videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ", "jNQXAC9IVRw"],
    "language": "en",
    "includeAutoGenerated": true,
    "includeSegments": false
}

Download the n8n workflow (JSON) — a manual trigger, the HTTP Request node above and a placeholder for your token.

Recipes

Turn a channel into a searchable knowledge base

Run the Actor with a Channel URL and a generous Max videos, then pass the run's dataset to RAG Text Chunker with the transcript run's dataset ID and text as the text field. You get token-counted chunks with the video URL attached, ready for embeddings and a vector database.

Timestamped quotes and chapter drafts

Keep segments on. Each segment has a start time in seconds, so a script can find the moment a phrase is said and link to it with https://www.youtube.com/watch?v=VIDEO_ID&t=754s. Grouping segments by minute or by topic gives you a first draft of chapters.

Summaries and content repurposing

Send text to the language model of your choice for summaries, show notes or social posts. Schedule a daily run on a channel URL and your summariser only processes the rows that are new.

How much does it cost?

Apify planPer videoPer 1,000
Free plan$0.004$4
Starter$0.0032$3.20
Scale$0.0028$2.80
Business$0.0024$2.40
Enterprise$0.0024$2.40
Enterprise+$0.0024$2.40

Primary event rates from a catalog snapshot; this is not the total price of a run. Additional charge events and Actor Start fees may apply; start fees can scale with memory. Check the Actor's Pricing tab on Apify for all events, conditions and current plan-specific rates, and set a maximum run budget before starting.

Videos with no captions return an error row with error: "no captions", and they are not charged. You pay only for transcripts you actually receive. Residential-proxy fallback adds a small per-video cost only when YouTube blocks the direct request.

Limits

  • Captions only. Views, likes and comments are not part of the output; use YouTube Video Details for video metadata.
  • Public videos only. Private videos return an error, and live chat messages are not included.
  • Languages are limited to the caption tracks YouTube offers. availableLanguages lists what a given video has.

FAQ

Do I need a YouTube API key?

No. The tool reads the captions YouTube serves for public videos. You only need an Apify account.

What happens if a video has no captions?

You get a row with error: "no captions" and no charge. Videos whose uploader turned captions off, and some age-restricted videos, fall into this group.

Can I get transcripts in another language?

Set language to the code you want, such as de or es. If that track does not exist, the fallback order above applies, and availableLanguages shows every language the video offers.

Does it work on private or unlisted videos?

Unlisted videos work when you have the URL. Private videos return an error, because their captions are not public.

Why does a long video take longer?

A two-hour video can have thousands of caption segments, and parsing them takes 10 to 20 seconds per video. That is normal. Split very large lists into several runs if you want results sooner.

Can an AI assistant use it directly?

Yes. Through the Apify MCP server, an assistant that supports MCP can run the Actor on a video link and read the transcript itself, for example to answer questions about a talk you have not watched.

Related tools

Workflows