Back

Blog details

Multi-Language Captions and Transcripts: A Developer Guide

AIOZ Network
7 min readSeptember 08, 2026
aioz-streamguide

The Chapter vs Transcript API article covered how one transcript file gets uploaded and marked default. This is what actually happens once a video has transcripts in five languages and different viewers need different ones by default, and it turns out the real answer depends on a browser behavior most developers building this don't realize they're relying on.

TL;DR:

  • Each language gets its own VTT file uploaded through the Transcript API, one per BCP 47 language code, with a single is_default flag that's global to the video, not personalized per viewer.
  • That global default sounds like a real limitation for serving different languages to different visitors, but the HTML spec itself hands most of the actual work to the browser: per MDN, a track marked default is "enabled unless the user's preferences indicate that another track is more appropriate."
  • The practical implication: upload every language a video needs, pick one sensible fallback as is_default, and let the browser's own language matching handle the rest, rather than trying to flip the default per request based on detected locale.
  • Regional BCP 47 variants (en-US vs en-GB, pt-BR vs pt-PT) matter when spelling or vocabulary genuinely differs, not as a default habit, most captions work fine tagged with a primary language code alone.
  • Nothing in AIOZ's documentation mentions Accept-Language headers or server-side locale detection, this is entirely a client-side, browser-native mechanism, not an AIOZ Stream feature to configure.

What multi-language actually requires, quickly

One call per language is the whole upload story: a POST to the Transcript API's create endpoint, per language code, each with its own VTT file. A video with English, Spanish, and Japanese transcripts is three separate uploads, three separate BCP 47 codes, not one multi-language file or a combined format, there's no single file format that carries multiple languages at once the way, say, a multi-track audio container might. Exactly one of those can be flagged is_default via the API's PATCH endpoint at any given time, AIOZ's own documentation is direct about what that flag does: "the default transcript is the transcript the player loads by default." Singular, one flag, one video, this isn't per-viewer or per-session, it's a stored property of the media object itself, the same way a video's title or description is one value shared by everyone who requests it, not something the API varies per request.

Video player interface showing multiple language subtitle options

The real constraint: one default, not one per viewer

This is worth being direct about rather than glossing over: nothing in AIOZ's Transcript API documentation mentions Accept-Language headers, geo-detection, or any mechanism for showing French viewers French by default and English viewers English by default automatically. The is_default flag is one setting, and whoever set it last is what every viewer gets unless they manually pick a different track themselves. A naive fix, detecting each viewer's locale server-side and calling the PATCH endpoint to flip the default before serving the page, technically works but creates a real race condition: two viewers with different locales requesting the same video near-simultaneously would each be changing a setting the other one just changed, with no guarantee either sees the right language.

Why the browser already handles most of this

The HTML specification for text tracks describes exactly the scenario multi-language captions run into, and hands the actual per-viewer decision to the browser, not the server. Per MDN's own documentation of the default attribute on a video's text track: "This attribute indicates that the track should be enabled unless the user's preferences indicate that another track is more appropriate." That's the mechanism that actually solves the per-viewer problem, not AIOZ's API. If every available language transcript is exposed to the player as its own track, a browser that knows the viewer's language preference, from their OS or browser language settings, is specced to prefer a matching track over whatever's marked default, not the other way around. The is_default flag matters specifically as the fallback for a viewer whose language preference doesn't match anything available, not as the primary mechanism serving each viewer the right transcript.

BCP 47 in practice: when regional variants actually matter

Both the Chapter and Transcript APIs accept regional variants like en-US or fr-CA alongside primary tags like en or fr, and it's worth having an actual rule for when to bother with the more specific tag rather than defaulting to it out of habit. Regional variants earn their keep when the content itself genuinely differs, British and American English spelling and vocabulary diverge enough that a captions team might localize separately, and Brazilian and European Portuguese differ enough in vocabulary that treating them as one language produces captions that read oddly to one audience or the other. For a video where the transcript would read identically regardless of region, the primary tag alone is the simpler, equally correct choice, extra regional variants only add value when there's an actual second version of the text to justify them. The W3C's own internationalization guidance states this as a general rule for language tags, not something specific to captions: "you should only use a region subtag if it contributes information needed in a particular context to distinguish this language tag from another one; otherwise leave it out," giving the same en-GB example as a case where the distinction earns its keep, spelling, while noting that a region subtag on, say, Japanese is unlikely to matter "unless you are intentionally contrasting it with Japanese spoken in other parts of the world." The golden rule the guidance states directly, keep the tag as short as possible and only extend it when the extension actually distinguishes something, applies to caption files exactly as it does to any other tagged content.

A practical multi-language workflow

Given all of the above, the workflow that actually holds up in production is simpler than trying to out-engineer the global-default constraint: upload a transcript for every language the video genuinely needs to support, pick whichever language the majority of the expected audience speaks as is_default, a true fallback choice, not a personalization attempt, and let every uploaded track render as its own option in the player. That leaves the browser's own spec-mandated preference matching to route each viewer to their actual language when one is available, with the single global default only ever surfacing for a viewer whose preference doesn't match anything on offer. Trying to dynamically rewrite is_default per request solves a problem the browser was already going to solve correctly, while introducing a real race condition that wasn't there before.

Concretely, for a video with English, Spanish, and Japanese transcripts aimed primarily at an English-speaking audience: upload all three via the Transcript API, one create call per language, then set en as is_default once, and leave it. A Spanish-speaking viewer whose browser is configured for Spanish gets the Spanish track automatically, per the same MDN-documented preference matching, without AIOZ Stream or the integrating application doing anything per-request to make that happen. The en default only actually surfaces for a viewer whose browser language doesn't match any of the three uploaded tracks, a French-language browser, for instance, with no French transcript available, at which point falling back to the primary audience's language is a reasonable default rather than an arbitrary one.

Frequently Asked Questions

Can AIOZ Stream show different default captions to different viewers automatically?
Not through the API. The is_default flag is a single, global setting per video; per-viewer language selection happens through the browser's own text-track preference matching, not through anything AIOZ Stream configures server-side.

Should I dynamically change is_default based on each viewer's detected locale?
Generally no. It creates a race condition between concurrent viewers with different locales and solves a problem the browser's native track-selection behavior already handles for any track that's actually available as an option.

How does a browser decide which caption track to show if I don't set anything?
Per the HTML spec, a browser prefers a track matching the user's own language preference over the one marked default, falling back to the default track only when no better match exists among the available options.

Do I need regional variants like en-US and en-GB, or is a plain language code enough?
A plain code like en is enough unless the transcript text genuinely differs by region, spelling, vocabulary, or dialect differences real enough to justify a separately localized file.

How many transcript files can one video have?
One per language code, per the Transcript API's own limit, at most one transcript per BCP 47 language tag for a given media object.

Does this same logic apply to chapters, not just transcripts?
Chapters don't have an is_default field or a default concept at all in AIOZ's API, this default/fallback discussion is specific to transcripts.

References

We only send updates when meaningful changes ship, and you can unsubscribe anytime

Related Content

blog thumbnail

Connecting an AI Agent to AIOZ Stream Without an MCP Server

AIOZ Stream still doesn't have an MCP server. That doesn't mean an AI agent can't use it today: tool calling, the mechanism MCP itself is built on, already gets you there, with a working example using AIOZ Stream's real API fields.

aioz-streamguide
6 min readSeptember 21, 2026
blog thumbnail

WebRTC Mesh vs SFU vs MCU: How P2P Video Topologies Actually Differ

Mesh, SFU, and MCU solve the same problem, getting N people in a call to see each other, in three very differently priced ways. The math behind why mesh breaks past 4 people, and why every major platform runs SFU instead of MCU.

aioz-streamguide
7 min readSeptember 20, 2026
blog thumbnail

What Is a CDN Edge Node and How Content Caching Actually Works

A traditional CDN edge is a company-owned data center, one of a few hundred. AIOZ's edge is a community-operated node, one of 328,094. Here's what that structural difference actually means for caching, coverage, and guarantees.

aioz-streamguide
6 min readSeptember 19, 2026
blog thumbnail

Video Container Formats Explained: MP4 vs MOV vs WebM vs MKV

MP4 and WebM aren't independent formats, they're restricted, standardized descendants of MOV and MKV. The real lineage explains the trade-offs better than a feature table, and none of the four is actually what a streaming platform delivers.

aioz-streamguide
7 min readSeptember 18, 2026
blog thumbnail

What Is AV1 and Should You Use It for Video Streaming

AV1 shares VP9's royalty-free pitch, but hardware decode is moving fast and Netflix's own numbers are strong. Here's what actually changed, and whether AIOZ Stream supports it today.

aioz-streamguide
6 min readSeptember 17, 2026
blog thumbnail

Widevine vs FairPlay vs PlayReady: DRM Explained

Most DRM comparisons stop at platform lists. The two things that actually matter: security tiers gate resolution, and a historical encryption mismatch used to break Apple playback silently, until the industry converged on one fix.

aioz-streamguide
6 min readSeptember 16, 2026