Skip to main content
SubtitleMatrix

VTT to JSON

Format conversionWebVTT (VTT)
Or paste subtitle text

What this conversion changes

1 thing is dropped or needs a decision

  • Format-specific content

    content the source format keeps outside its cues (non-cue blocks, header text, per-cue settings, commented-out events) — the target format has no place for it

This list comes from the capability matrix for these two formats, not from the particular file you loaded. A specific file may lose more if it uses features the format allows but the matrix does not model.

This page converts WebVTT to JSON. Drop a file in — or paste the text — and you get back a plain JSON document describing the same subtitles. The conversion runs entirely in your browser: nothing is uploaded, no account is needed, and the page keeps working with the network switched off once it has loaded.

The JSON is this site's own documented subtitle schema, and it is deliberately shaped after the cue model the whole converter works in: a version number, then one entry per cue with its identifier, its start and end in integer milliseconds, and its lines as arrays of text with inline spans. Times stay integer milliseconds rather than being rewritten as timecodes, and a cue's lines stay separate instead of being joined, so the output is meant to be read by your own script rather than by a video player.

Almost everything WebVTT stores is expressible in that shape, which is why the report above is short. What has no key in the JSON is what lives outside the cues: the WEBVTT header and any comment on it, the NOTE, STYLE and REGION blocks, and the settings that can follow a timestamp such as align:start. Those are dropped, not tucked into a spare field, and the report above counts them in your file before you download it. Cue identifiers are the exception in the other direction: unlike SRT, this schema has an id field, so intro stays intro.

Awkward input is fine: a missing header, Windows line endings, a stray line before a timestamp or a byte-order mark are all read without complaint. Drop in one file or a whole season; the queue works through them in order, you can stop it part-way, and the results come down together as a single ZIP.

Examples

A typical VTT file, converted to JSON

Input

WEBVTT

intro
00:00:01.000 --> 00:00:04.000
Hello there.

00:00:04.500 --> 00:00:08.000 align:start position:10%
Second line with <i>italics</i>.

Output

{
  "version": 1,
  "cues": [
    {
      "id": "intro",
      "start": 1000,
      "end": 4000,
      "lines": [
        "Hello there."
      ]
    },
    {
      "start": 4500,
      "end": 8000,
      "lines": [
        {
          "text": "Second line with italics.",
          "tags": [
            {
              "kind": "italic",
              "start": 17,
              "end": 24
            }
          ]
        }
      ]
    }
  ]
}

Dropped in this output: format-specific content. Everything else matches line for line.

The same conversion on an awkward input

Input

a stray comment line
cue-id-1
00:00:01.000 --> 00:00:02.000
No header, two lines before the timecode.

Output

{
  "version": 1,
  "cues": [
    {
      "start": 1000,
      "end": 2000,
      "lines": [
        "No header, two lines before the timecode."
      ]
    }
  ]
}

This is the kind of damage real files have — mixed line endings, stray whitespace, fields left empty. Compare it with the tidy example above to see what the parser forgives.

Frequently asked questions

What does the JSON look like?

A version number and a cues array. Each cue has an optional id, a start and an end in integer milliseconds, and a lines array where each line is either a string or an object with the text plus the spans it carries — italics, bold and the like — as start and end offsets. There are no timecodes to parse and no centiseconds to watch out for.

Why is the list of dropped items so short here?

Because the schema was built to hold everything the converter's cue model can carry, which covers nearly all of what WebVTT has. What is left over is the material WebVTT keeps outside the cues themselves: the header, its comment, the NOTE, STYLE and REGION blocks, and the per-cue settings.

Are the cue identifiers kept?

Yes. WebVTT allows a free-form identifier such as intro or sign-1 before a cue, and this schema has an id field for it, so it is written out unchanged. Converting to SRT instead would renumber the cues, because SRT's counter has to be numeric.

Do the timings change at all?

No. Both sides work in whole milliseconds, so 00:00:01.234 becomes 1234 and back again with nothing rounded and nothing shifted.

Is it safe to run a transcript through this page?

Yes. Parsing and writing happen in the browser, so the file you drop here is never sent to a server — which matters more than usual for this pair, because JSON is what a script or a pipeline consumes, and those are often the transcripts that cannot leave the building.

Related tools