Turn WebVTT (.vtt) subtitle files into CSV for easier editing, review, and spreadsheet workflows—right in your browser.
.vtt file or click "Add Files" to browse. Parsing happens in your browser — nothing leaves your device. Batch conversion is supported, so you can drop a multi-episode caption bundle and download one CSV per file (or stitch them after).<v Speaker> voice tag (when present), and cue text — then writes one row per cue with a header line for the spreadsheet.WEBVTT header, NOTE comments, STYLE blocks, and REGION blocks are dropped because they don't map to tabular data. Cue settings such as line:, position:, align:, vertical:, and size: are also stripped. Inline tags like <b>, <i>, <u>, <c.classname>, and <ruby> are removed from the text column so the spreadsheet reads as plain prose..csv file downloads immediately as UTF-8 with comma separators and RFC 4180 quoting, ready to open in Excel, Google Sheets, Numbers, or any pandas/R/SQL import pipeline.WebVTT is a W3C-standardised plain-text format built for the HTML5 <track> element — its cues, settings, and STYLE blocks make sense to a browser but not to a spreadsheet. CSV flattens each cue into a row of plain values: index, start, end, speaker, text. Once your captions live in tabular form, every analytics, translation, and search tool that already speaks CSV can ingest them without a custom parser.
LEN(text) / (end_seconds - start_seconds), and flag any row over your threshold.Ctrl+F or filter-by-keyword finds every occurrence of a term across an entire course in seconds, with timestamps to jump back to the video.COPY, MySQL LOAD DATA INFILE, BigQuery, and Snowflake all consume CSV natively. Loading a year of podcast transcripts into a searchable database starts with a VTT-to-CSV pass..vtt file looking for typos. In a spreadsheet they can sort by length, filter by speaker, freeze the timestamp column, and tab through rows with the keyboard.Need a different starting format? Try SRT to CSV if your captions came from a desktop editor, TTML to CSV for broadcast deliveries, or ASS to CSV for anime/fansub sources. Reverse the direction with CSV to VTT once you've finished editing.
| Property | VTT (WebVTT) | CSV |
|---|---|---|
| Standardised by | W3C webvtt1 Candidate Recommendation Draft |
RFC 4180 (informational) |
| File extension | .vtt |
.csv |
| MIME type | text/vtt |
text/csv |
| Structure | Cue blocks separated by blank lines | One row per record, comma-separated |
| Timestamps | Required, hh:mm:ss.ttt or mm:ss.ttt |
Free-form column (kept as text by default) |
| Header line | Required: WEBVTT |
First row is column names (by convention) |
| Inline tags | <b> <i> <u> <c> <v> <ruby> <lang> |
None — plain text only |
| Cue settings | line: position: align: vertical: size: |
Not representable |
| STYLE / REGION / NOTE blocks | Yes — embedded CSS, regions, comments | Not representable |
| Reading-speed analysis | Requires custom parser | One formula in any spreadsheet |
| Tooling | HTML5 video players, captioning editors | Excel, Google Sheets, pandas, SQL, R, jq |
| Encoding | UTF-8 (mandated by spec) | UTF-8 recommended; legacy tools sometimes default to CP1252 |
The output is a standard comma-separated file with a header row. One WebVTT cue becomes one row:
| Column | Source in the VTT cue | Example value |
|---|---|---|
index |
1-based sequential counter | 1, 2, 3 |
identifier |
Optional cue identifier line (the line before the timestamp) | cue-12, intro, or blank if absent |
start |
Start timestamp before the --> |
00:00:22.230 |
end |
End timestamp after the --> |
00:00:24.606 |
speaker |
Content of <v Speaker>...</v> voice tag, if present |
Alice, blank if none |
text |
Cue payload with inline tags stripped, line breaks joined with a space | Welcome to the show. |
The first row is the header (index,identifier,start,end,speaker,text). Values containing commas, double quotes, or line breaks are wrapped in double quotes per RFC 4180; embedded quotes are doubled (""). The file is written as UTF-8 without a BOM, which is what Google Sheets, modern Excel (Microsoft 365 and Excel 2019+), Numbers, and pandas all expect.
By default: index, identifier, start, end, speaker, text. The index column is a 1-based counter the converter adds (WebVTT cue numbering is optional in the spec). The identifier column carries any non-numeric cue ID from your source file and is blank when the cue had none. The speaker column is populated only when a cue uses a <v Speaker> voice tag — otherwise it's empty. If you need only start, end, text, delete the unwanted columns in Excel after export; the rows themselves are untouched.
<b> and <i> missing in the CSV?Because CSV is plain text — there's no way to render bold or italics in a spreadsheet cell. The converter strips <b>, <i>, <u>, <c.class>, <ruby>, <rt>, <lang>, and timestamp tags from the text column so the prose reads cleanly when imported. Plain characters (including emoji and accented characters) are preserved exactly. If you need to keep the markup, convert to VTT to SRT or VTT to TXT instead — SRT preserves the supported tags verbatim.
They're discarded. NOTE blocks are author comments not intended for display, STYLE blocks contain CSS that has no meaning in a spreadsheet, and REGION blocks define on-screen positioning that CSV can't represent. The converter walks the file per the W3C parsing rules, recognises these block types, and skips them — only actual cues become rows.
Exactly as they appear in the source VTT: hh:mm:ss.ttt when the cue has hours (e.g., 01:23:45.678) or mm:ss.ttt when it doesn't (e.g., 02:15.500). Excel and Google Sheets both treat these as text strings, which is what you want — leave them alone if you're just searching or editing, or convert to seconds in a formula (=TIMEVALUE(...)*86400) when you need numeric math for reading-speed audits.
No. The converter follows RFC 4180 quoting: any field containing a comma, a double quote, or a CR/LF gets wrapped in double quotes, and any embedded double quote is escaped as "". Modern Excel, Google Sheets, LibreOffice Calc, Numbers, and the Python csv module all parse this correctly. If you're using a legacy importer that chokes on quoted fields, open the CSV in a text editor and you'll see the quoting is well-formed.
Almost always an encoding mismatch. The converter writes UTF-8 without a BOM. Excel on Windows still defaults to CP1252 when you double-click a .csv, so accented characters and CJK glyphs render as mojibake. Two fixes: (1) in Excel, use Data → From Text/CSV and explicitly pick 65001: Unicode (UTF-8) in the dialog; or (2) save a copy of the CSV with a UTF-8 BOM (EF BB BF at the start) and Excel will autodetect it. Google Sheets and Numbers both autodetect UTF-8 without help.
The default is one row per cue, which mirrors the WebVTT source 1:1. For per-word output you'd need WebVTT timestamp tags inside cues (<00:01:23.500>word) — those are stripped during conversion. If your VTT was generated by a speech-to-text engine that emits word-level cues (each word is its own cue), the CSV will already have one word per row. For per-sentence output, run the conversion and then split rows on sentence boundaries in your spreadsheet or pandas DataFrame.
NOTE Speaker: lines too?No — only from <v Speaker>...</v> voice tags inside cues, which is the W3C-defined mechanism for marking who's talking. Many transcription tools embed speaker names inline in the text instead (Alice: Welcome back.) — in that case the speaker column stays blank and the name lives in the text column. You can split it out with =LEFT(F2, FIND(":", F2)-1) in Excel or df['text'].str.split(':', n=1, expand=True) in pandas.
Yes — that's what CSV to VTT is for. Edit the text column, save as CSV (UTF-8), and the reverse converter rebuilds a valid WebVTT file with the WEBVTT header, the original timestamps, and any speaker tags wrapped back into <v> syntax. This is the standard translation round-trip: VTT → CSV → translator works in Excel → CSV → VTT.
No. The VTT is parsed and the CSV is generated entirely in your browser session — there's no upload, no account, no watermark, and no rate limit. The file is deleted when you close the tab.