Blog / Tutorials / YouTube Transcript Export Schema: JSON, JSONL, CSV
Tutorials 6 min read â€ĸ November 13, 2026

YouTube Transcript Export Schema: JSON, JSONL, CSV

Founder

Every structured export format — json, jsonl, and csv — shares the same 22 columns, one row per video (or per stored caption track, if you export ?language=all). This is the field-by-field reference for writing a parser against GET /api/v1/transcripts/{batch_id}/export.

All three formats carry identical data — picking between them is purely about what's downstream: json for loading a whole batch into memory at once, jsonl for streaming processing or appending to a line-oriented data pipeline, csv for spreadsheets or anything expecting tabular input.

The columns

FieldMeaning
video_id, url, title, channel, channel_idVideo identity.
duration_seconds, view_count, like_count, comment_count, published_atVideo stats, from include_metadata.
description, tagsThe video's YouTube description and tag list.
transcript_languageWhich caption language this row is.
caption_sourcemanual (creator-uploaded) or asr (YouTube auto-generated).
is_generatedBoolean version of the same thing.
transcript_source, translation_sourceHow the text was obtained — e.g. a straight YouTube fetch vs. a Google translation.
versionArchive version of the stored transcript (see GET /videos/{id}/transcripts?include_versions=true for older ones).
textThe transcript itself.
status, error_code, errorSet on failed/skipped items instead of a transcript — see below.

Timecoded segments are not in these exports — they're flat, one row per video. For {text, start, duration} segments, use include_segments=true on the batch poll (GET /api/v1/transcripts/{batch_id}) instead, or export srt/vtt directly; see every way to get timestamps.

JSON — an array of rows

curl -s "https://scriptube.me/api/v1/transcripts/BATCH_ID/export?format=json" \
  -H "X-API-Key: YOUR_API_KEY"
[
  {
    "video_id": "dQw4w9WgXcQ",
    "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "title": "Rick Astley - Never Gonna Give You Up",
    "channel": "Rick Astley",
    "channel_id": "UCuAXFkgsw1L7xaCfnd5JJOw",
    "duration_seconds": 213,
    "view_count": 1600000000,
    "like_count": 18000000,
    "comment_count": 2100000,
    "published_at": "2009-10-25",
    "description": "The official video...",
    "tags": ["rick astley", "never gonna give you up"],
    "transcript_language": "en",
    "caption_source": "manual",
    "is_generated": false,
    "transcript_source": "youtube_free",
    "translation_source": null,
    "version": 1,
    "text": "We're no strangers to love...",
    "status": "completed",
    "error_code": "",
    "error": ""
  }
]

Note the top-level value is a JSON array, not one object per line — don't try to stream-parse it line by line.

JSONL — one object per line

curl -s "https://scriptube.me/api/v1/transcripts/BATCH_ID/export?format=jsonl" \
  -H "X-API-Key: YOUR_API_KEY"
{"video_id": "dQw4w9WgXcQ", "url": "...", "title": "...", "status": "completed", "text": "We're no strangers to love...", ...}
{"video_id": "abc123XYZde", "url": "...", "title": "...", "status": "failed", "error_code": "transcripts_disabled", "error": "...", "text": ""}

This is the one to reach for when you're processing results with a streaming parser, or loading rows straight into a data pipeline — no need to buffer the whole array in memory first.

CSV — same columns, as a header row

curl -s "https://scriptube.me/api/v1/transcripts/BATCH_ID/export?format=csv" \
  -H "X-API-Key: YOUR_API_KEY" -o export.csv
video_id,url,title,channel,channel_id,duration_seconds,view_count,like_count,comment_count,published_at,description,tags,transcript_language,caption_source,is_generated,transcript_source,translation_source,version,text,status,error_code,error
dQw4w9WgXcQ,https://www.youtube.com/watch?v=dQw4w9WgXcQ,Rick Astley - Never Gonna Give You Up,Rick Astley,UCuAXFkgsw1L7xaCfnd5JJOw,213,1600000000,18000000,2100000,2009-10-25,"The official video...","[""rick astley"", ""never gonna give you up""]",en,manual,False,youtube_free,,1,"We're no strangers to love...",completed,,

The tags column is a JSON array serialized as a single string (quoted and escaped), not a Python list — parse it as JSON, not as a comma-split field, or a video with multiple tags will look like extra columns. See opening CSV exports in Excel or Sheets for the spreadsheet side of this.

Per-item export

If you need one video's row rather than the whole batch, GET /api/v1/transcripts/{batch_id}/items/{item_id}/export returns the same schema for a single item — useful when a webhook's transcript.ready event hands you an item_id and you want just that row without pulling the whole batch.

Reading multiple languages per video

By default you get one row per video: the primary stored track (human captions before auto-generated, newest version). Pass ?language=all and a video with three stored caption tracks produces three rows instead of one, each with its own transcript_language and text — handy for a dataset that needs every language Scriptube has fetched for a video, not just the default. Without all, ?language=es picks one specific track and falls back to the default if that video doesn't have Spanish stored.

Failed and skipped items

By default (include_failed=true), a video that errored out still gets a row — status set to failed or skipped, error_code set to a machine-readable reason (e.g. transcripts_disabled, video_unavailable), text empty. Pass include_failed=false to drop them and get completed-only rows. Exporting a batch that's still running needs partial=true explicitly, or the export is refused until it finishes.

This matters for parsers more than it might seem: code that assumes every row has a non-empty text field will crash or silently produce garbage the first time it hits a real batch with any failures in it. Branch on status before touching text, every time.

Encoding and escaping, per format

FormatHow the transcript text is escaped
JSON / JSONLStandard JSON string escaping — quotes, newlines, and unicode are handled by any JSON parser automatically.
CSVRFC 4180 quoting — a field containing a comma, quote, or newline is wrapped in double quotes, with internal quotes doubled. Use a real CSV parser (not split(",")), since transcript text routinely contains commas.

A transcript longer than a typical spreadsheet cell limit (Excel caps a cell around 32,767 characters) can be truncated when opened in Excel specifically — this is an Excel limitation on the receiving end, not something the export does. Long-form content is usually fine in Google Sheets or when read programmatically with pandas or a CSV library.

Next steps

Full reference: API documentation.

Try Scriptube Free

Extract YouTube transcripts instantly. No credit card required.

Get Started

Related Articles

Tutorials

Your YouTube Transcript Library: Find Everything You've Already Processed

Every video you've ever submitted to Scriptube stays in your library — browsable by channel and playlist, searchable when you need to find something you...

Tutorials

How to Retry Failed YouTube Transcripts Without Resubmitting the Batch

A batch of 50 videos rarely comes back 50 for 50 — a couple of videos might have no captions, one might hit a rate limit, another might just need a second...

Tutorials

YouTube Transcript API: The Complete Guide

The Scriptube API lets you submit YouTube video, playlist, or channel URLs and get back transcripts and metadata as JSON, CSV, or JSONL, plus timed segments...