Transcript generator › API
YouTube transcript API
One GET request. Six output formats. No key, no SDK, no sign-up — the same endpoint this site's own tool calls.
Quick start
curl "https://youtubegpt.ai/api/transcript?v=aircAruvnKk&format=txt"
That is the whole API. Everything below is detail.
Not the Python package
Searching this term usually turns up youtube-transcript-api, the Python package by
jdepoix that has been maintained since 2018. It is a good library and this is not a replacement for it.
The difference is where the work happens: the package runs the extraction from wherever your code runs,
so it inherits your machine's IP reputation and you maintain it as YouTube changes. This is a hosted
HTTP endpoint — no install, no language lock-in, and the extraction runs from an IP that is kept working
on our side. Reach for the package when you want no external dependency and control over the internals;
reach for this when you want one GET request from any language, or when self-hosted extraction has
started returning empty results.
Endpoint
GET https://youtubegpt.ai/api/transcript
Parameters
| Name | Required | Description |
|---|---|---|
url or v | yes | A YouTube URL in any common shape, or the bare 11-character video ID. Watch links, youtu.be short links, Shorts and embed URLs all parse. |
format | no | Output format. Defaults to json. See the table below. |
lang | no | Preferred caption language, e.g. en, es, ja. Defaults to en. Falls back to a human track, then an auto track, then English, then whatever exists. |
download | no | Set to 1 to receive a Content-Disposition attachment header with a filename derived from the video title. |
Formats
format | Content-Type | Description |
|---|---|---|
json | application/json | Full structure: video metadata, chosen track, all available tracks, and every segment with millisecond timings |
txt | text/plain | One continuous block, no timecodes, no line breaks |
paragraphs | text/plain | Fragments reassembled into readable paragraphs |
txt-timestamps | text/plain | One line per caption, prefixed [m:ss] |
llm | text/markdown | Title, channel, duration and source URL as a header, then paragraphs with timestamp anchors |
srt | application/x-subrip | SubRip subtitle file |
vtt | text/vtt | WebVTT subtitle file |
JSON response
{
"ok": true,
"video": {
"id": "aircAruvnKk",
"title": "But what is a neural network?",
"author": "3Blue1Brown",
"durationSeconds": 1140,
"thumbnail": "https://i.ytimg.com/vi/…"
},
"track": {
"language": "en",
"name": "English",
"generated": false
},
"availableTracks": [
{ "language": "en", "name": "English", "generated": false },
{ "language": "es", "name": "Spanish", "generated": false }
],
"segments": [
{ "start": 4200, "dur": 3160, "text": "This is a 3." }
]
}
start and dur are milliseconds. dur may be null on the
final segment of some tracks, which is how the upstream caption data arrives; treat it as
"until the next segment" if you need an end time.
generated: true means the track came from speech recognition rather than a human.
Worth surfacing to your users — auto tracks mishear names, jargon and anything spoken over music.
Examples
JavaScript
const res = await fetch(
'https://youtubegpt.ai/api/transcript?v=aircAruvnKk&format=json'
);
const data = await res.json();
if (!data.ok) throw new Error(data.message);
console.log(data.video.title, data.segments.length + ' segments');
Python
import urllib.request, json
url = "https://youtubegpt.ai/api/transcript?v=aircAruvnKk&format=json"
data = json.load(urllib.request.urlopen(url))
if not data.get("ok"):
raise RuntimeError(data["message"])
text = " ".join(s["text"] for s in data["segments"])
print(data["video"]["title"], len(text.split()), "words")
Feeding a language model
The llm format exists for exactly this. It ships the title, channel, duration and
source URL as a header, so the model is not guessing at context, and puts a timestamp anchor
on each paragraph so it can cite specific moments back:
curl -s "https://youtubegpt.ai/api/transcript?v=VIDEO_ID&format=llm" \
| llm "Summarise this talk in five bullet points, citing timestamps"
Errors
Failures return a non-2xx status with a JSON body carrying a stable code and a
human-readable message. Branch on code, display message.
{ "ok": false, "code": "no_captions", "message": "..." }
| Code | HTTP | Meaning |
|---|---|---|
bad_input | 400 | Could not parse a video ID from what you sent |
bad_format | 400 | format is not one of the supported values |
no_captions | 404 | The video has no caption track at all |
not_found | 404 | The video ID does not resolve |
login_required | 451 | Age-restricted or private; captions unreachable without a signed-in session |
unplayable | 451 | Blocked, removed, or otherwise unplayable |
offline | 409 | A live stream that has not finished |
empty | 502 | A track exists but returned no content |
node_unreachable | 503 | The extraction node is down — retry shortly |
Handle no_captions as a normal outcome
It is not a bug or an outage — plenty of videos genuinely have no caption track, and no tool can produce a transcript from one. This API reads captions that already exist; it does not run speech recognition. Build the empty case into your flow rather than treating it as a failure.
Practical notes
Caching and rate
Successful responses carry Cache-Control: public, max-age=3600, so repeated requests
for the same video are cheap. Please cache on your side too. There is no hard published rate limit;
extraction is real work against upstream, so batch politely — a short pause between requests rather
than firing hundreds in parallel.
CORS
Responses include Access-Control-Allow-Origin: *, so you can call it straight from
browser JavaScript without a proxy of your own.
Long videos
No length cap. The longest video in our testing was a 266-minute course, which returned 2,935 segments and 50,862 words in a single response. Allow a generous client timeout for videos of that size.
Rights
The transcript is the video creator's words, and this API does not transfer any rights to them. Whatever you build on top should credit the source video and link back to it.
Frequently asked
Do I need an API key?
No. There is no key, no account and no SDK — it is a plain GET request.
Can I use it in production?
It is a free public endpoint with no uptime guarantee. Cache aggressively, handle the error codes above, and do not build something where a failed transcript fetch breaks your whole product.
How do I get a transcript in a specific language?
Pass lang. Request format=json first if you need to know what exists — availableTracks lists every track on the video.
Can it transcribe a video that has no captions?
No. It reads existing caption tracks. A video with no captions returns no_captions.
How do I fetch many videos?
Call it once per video ID, sequentially or with modest concurrency, and cache the results. There is no batch parameter.
More guides
Independent tool. youtubegpt.ai is not affiliated with, endorsed by, or operated by YouTube or Google. It works with publicly available caption data from YouTube and does not host, mirror or re-upload any video. Transcript text belongs to the original video creators. "YouTube" is a trademark of Google LLC.