Subtitles
Transcodely supports flexible subtitle processing as part of your transcoding outputs. You can pass through existing subtitle tracks, convert between formats, burn subtitles directly into the video, or extract embedded subtitles as sidecar files.
Subtitle tracks are configured in the subtitle_tracks array of an Output Specification. Each output can include up to 8 subtitle tracks.
The SubtitleTrack object
| Attribute | Type | Required | Description |
|---|---|---|---|
operation | enum | Yes | Subtitle operation. One of: passthrough, convert, burn_in, extract. See Operations. |
source_stream_index | integer | One of | Index of the subtitle stream in the input file (0—31). Mutually exclusive with source_url. |
source_url | string | One of | URL to an external subtitle file. Supported schemes: gs://, s3://, https://. Mutually exclusive with source_stream_index. Max 2048 characters. |
input_format | enum | No | Input subtitle format. One of: srt, webvtt, ttml, ass. Auto-detected when omitted. |
output_format | enum | No | Output subtitle format. One of: srt, webvtt, ttml, ass. Required for convert and extract operations. |
language | string | No | ISO 639-2 three-letter language code (e.g., eng, spa, fra, deu). |
label | string | No | Human-readable label (e.g., "English", "Spanish (Latin America)"). Max 64 characters. |
is_default | boolean | No | Mark as the default subtitle track for the player. |
hearing_impaired | boolean | No | Flag for hearing-impaired / closed caption tracks (SDH). |
forced | boolean | No | Flag for forced subtitles (e.g., foreign-language dialogue in an otherwise native-language film). |
burn_in_style | object | No | Styling for burn-in subtitles. Only valid when operation is burn_in. See Burn-in styling. |
{
"operation": "convert",
"source_url": "gs://my-bucket/subs/english.srt",
"input_format": "srt",
"output_format": "webvtt",
"language": "eng",
"label": "English",
"is_default": true
}Operations
Each subtitle track requires exactly one operation that determines how Transcodely processes it.
| Operation | Description | Source | Output |
|---|---|---|---|
passthrough | Copy the subtitle track to the output without modification. | source_stream_index or source_url | Preserves original format. |
convert | Convert between subtitle formats. | source_stream_index or source_url | output_format required. |
burn_in | Render subtitles directly into the video frames. Produces a hard-subbed video — subtitles cannot be turned off by the viewer. | source_stream_index or source_url | No sidecar file produced. burn_in_style optional. |
extract | Extract an embedded subtitle stream as a standalone sidecar file. | source_stream_index only | output_format specifies the sidecar file format. |
Note: The
extractoperation only acceptssource_stream_indexsince it extracts subtitles already embedded in the input file. Useconvertwithsource_urlfor external subtitle files.
Formats
Transcodely supports four subtitle formats for input and output.
| Format | API Value | Extension | Description |
|---|---|---|---|
| SRT | srt | .srt | SubRip Text. The most common subtitle format. Plain text with timestamps. Widely supported by all players. |
| WebVTT | webvtt | .vtt | Web Video Text Tracks. Standard for HTML5 <video> and HLS/DASH streaming. Supports styling and positioning. |
| TTML | ttml | .ttml | Timed Text Markup Language. XML-based format used in broadcast, DASH, and IMSC1 (Netflix, Disney+). |
| ASS | ass | .ass | Advanced SubStation Alpha. Rich formatting with fonts, colors, and animations. Common in anime and fansubs. |
Format compatibility
Not all format conversions are lossless. Converting from a rich format to a simpler one may discard styling information:
| From | To | Notes |
|---|---|---|
srt | webvtt | Lossless. SRT is a subset of WebVTT. |
webvtt | srt | Positioning and styling cues are stripped. |
ass | srt / webvtt | Rich formatting (fonts, colors, animations) is stripped. |
ttml | srt / webvtt | XML styling and layout is stripped. |
srt / webvtt | ttml | Text content is preserved; no styling added. |
Source options
Every subtitle track requires a source — either an embedded stream from the input file or an external subtitle file. The two modes are mutually exclusive.
Embedded stream
Use source_stream_index to reference a subtitle stream embedded in the input file by its zero-based index. Use Input Metadata to discover available subtitle streams and their indices.
{
"operation": "passthrough",
"source_stream_index": 0,
"language": "eng",
"label": "English"
}External file
Use source_url to reference a standalone subtitle file by URL. Supported schemes: gs://, s3://, and https://. The subtitle file is downloaded and processed alongside the video.
{
"operation": "convert",
"source_url": "gs://my-bucket/subs/spanish.srt",
"input_format": "srt",
"output_format": "webvtt",
"language": "spa",
"label": "Spanish"
}Burn-in styling
The burn_in_style object controls the appearance of burned-in subtitles. All fields are optional with sensible defaults.
| Attribute | Type | Default | Description |
|---|---|---|---|
font_family | string | "Arial" | Font family name. Max 64 characters. |
font_size | integer | 24 | Font size in pixels (8—120). |
font_color | string | "#FFFFFF" | Text color as hex (e.g., "#FFFFFF" for white). |
outline_color | string | "#000000" | Outline color as hex (e.g., "#000000" for black). |
outline_width | integer | 2 | Outline thickness in pixels (0—10). Set to 0 for no outline. |
margin_bottom | integer | 30 | Bottom margin in pixels (0—200). Distance from the bottom of the video frame. |
{
"burn_in_style": {
"font_family": "Helvetica",
"font_size": 28,
"font_color": "#FFFF00",
"outline_color": "#000000",
"outline_width": 3,
"margin_bottom": 40
}
}Tip: For maximum readability across different video content, use a white font with a black outline (
outline_widthof 2—3). Increasefont_sizefor 4K outputs where the default 24px may appear small.
Examples
Passthrough embedded subtitle
Pass through an embedded subtitle track from the input file into an HLS output without modification.
{
"type": "hls",
"video": [
{"codec": "h264", "resolution": "1080p", "quality": "standard"}
],
"subtitle_tracks": [
{
"operation": "passthrough",
"source_stream_index": 0,
"language": "eng",
"label": "English",
"is_default": true
}
]
}Convert SRT to WebVTT
Convert an external SRT file to WebVTT format for HLS streaming compatibility.
{
"type": "hls",
"video": [
{"codec": "h264", "resolution": "1080p", "quality": "standard"}
],
"subtitle_tracks": [
{
"operation": "convert",
"source_url": "gs://my-bucket/subs/english.srt",
"input_format": "srt",
"output_format": "webvtt",
"language": "eng",
"label": "English",
"is_default": true
}
]
}Burn-in with custom styling
Burn subtitles directly into the video frames with custom font, color, and positioning. The resulting video will have permanently visible subtitles.
{
"type": "mp4",
"video": [
{"codec": "h264", "resolution": "1080p", "quality": "standard"}
],
"subtitle_tracks": [
{
"operation": "burn_in",
"source_url": "https://cdn.example.com/subs/spanish.srt",
"language": "spa",
"burn_in_style": {
"font_family": "Helvetica",
"font_size": 28,
"font_color": "#FFFF00",
"outline_color": "#000000",
"outline_width": 3,
"margin_bottom": 40
}
}
]
}Multi-language streaming with SDH
Configure multiple subtitle tracks for adaptive streaming, including hearing-impaired and forced subtitle variants.
{
"type": "adaptive",
"video": [
{"codec": "h264", "resolution": "1080p", "quality": "standard"},
{"codec": "h264", "resolution": "720p", "quality": "standard"}
],
"subtitle_tracks": [
{
"operation": "convert",
"source_url": "gs://my-bucket/subs/en.srt",
"output_format": "webvtt",
"language": "eng",
"label": "English",
"is_default": true
},
{
"operation": "convert",
"source_url": "gs://my-bucket/subs/en-sdh.srt",
"output_format": "webvtt",
"language": "eng",
"label": "English (SDH)",
"hearing_impaired": true
},
{
"operation": "convert",
"source_url": "gs://my-bucket/subs/es.srt",
"output_format": "webvtt",
"language": "spa",
"label": "Spanish"
},
{
"operation": "passthrough",
"source_stream_index": 2,
"language": "fra",
"label": "French (Forced)",
"forced": true
}
]
}Validation rules
Transcodely validates subtitle track configuration at job creation time. The following constraints are enforced:
| Rule | Description |
|---|---|
| Maximum 8 tracks | Each output supports up to 8 subtitle_tracks entries. |
| Mutually exclusive source | Exactly one of source_stream_index or source_url must be set per track. |
extract requires stream index | The extract operation only accepts source_stream_index, not source_url. |
convert requires output format | The convert operation requires output_format to be set. |
burn_in_style requires burn-in | The burn_in_style object is only valid when operation is burn_in. |
| Language format | language must be a valid ISO 639-2 three-letter code matching ^[a-z]{3}$. |
| Stream index range | source_stream_index must be between 0 and 31 (inclusive). |
| URL schemes | source_url must use gs://, s3://, or https:// scheme. Max 2048 characters. |
| Label length | label must not exceed 64 characters. |