Use the @mux/ai library to automatically translate video captions into different languages via LLMs
Mux uses OpenAI's Whisper model to create auto-generated captions, which must be generated in the same language as your source audio. To make your content accessible globally, you can use AI to translate captions into other languages. The @mux/ai library makes this straightforward by handling caption fetching, translation, and re-uploading to Mux.
Before starting, make sure you have:
npm install @mux/aiSet your environment variables:
# Required for Mux
MUX_TOKEN_ID=your_mux_token_id
MUX_TOKEN_SECRET=your_mux_token_secret
# You only need the API key for the provider you're using
OPENAI_API_KEY=your_openai_api_key # OR
ANTHROPIC_API_KEY=your_anthropic_api_key # OR
GOOGLE_GENERATIVE_AI_API_KEY=your_google_api_key
# Required for uploading translated captions back to Mux
S3_ENDPOINT=https://your-s3-endpoint.com
S3_REGION=auto
S3_BUCKET=your-bucket-name
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-keyimport { translateCaptions } from "@mux/ai/workflows";
// Translate English captions to Spanish
const result = await translateCaptions(
"your-mux-asset-id",
"en", // source language
"es", // target language
{
provider: "anthropic" // or "openai" or "google"
}
);
console.log(result.uploadedTrackId);
// The new Mux track ID for the translated captionsThe function automatically:
@mux/ai uses ISO 639-1 language codes and automatically converts them to full language names. It supports all standard language codes, but the translation capability of your chosen AI provider may vary.
// Common translations
await translateCaptions("your-mux-asset-id", "en", "es"); // English → Spanish
await translateCaptions("your-mux-asset-id", "en", "fr"); // English → French
await translateCaptions("your-mux-asset-id", "en", "de"); // English → German
await translateCaptions("your-mux-asset-id", "en", "ja"); // English → Japanese
await translateCaptions("your-mux-asset-id", "en", "zh"); // English → Chinese
await translateCaptions("your-mux-asset-id", "en", "ar"); // English → Arabic
// etc.@mux/ai supports three AI providers:
gpt-5-mini model - Fast and cost-effectiveclaude-sonnet-4-5 model - Excellent for nuanced translationsgemini-2.5-flash model - Balance of speed and qualityconst result = await translateCaptions("your-mux-asset-id", "en", "es", {
provider: "anthropic",
model: "claude-opus-4-5" // Optional: override default model
});If you want to handle the upload yourself or just get the translated file:
const result = await translateCaptions("your-mux-asset-id", "en", "es", {
uploadToMux: false
});
console.log(result.presignedUrl);
// URL to download the translated VTT file for review before uploading to MuxFor automated translation when videos are uploaded, you should trigger the call to translate captions from the video.asset.track.ready webhook for your source language:
export async function handleWebhook(req, res) {
const event = req.body;
if (event.type === 'video.asset.track.ready' &&
event.data.type === 'text' &&
event.data.language_code === 'en') {
const result = await translateCaptions(event.data.asset_id, "en", "es");
await db.saveTranslationTrack(event.data.asset_id, result.uploadedTrackId);
}
}Mux Player automatically detects multiple caption tracks and shows a language selector:
<mux-player
playback-id="your-playback-id"
metadata-video-title="My Video"
></mux-player>Users can switch between languages using the captions menu in the player controls.
Here's a complete webhook handler that translates captions:
import express from 'express';
import { translateCaptions } from "@mux/ai/workflows";
const app = express();
app.use(express.json());
app.post('/webhook', async (req, res) => {
const event = req.body;
if (event.type === 'video.asset.track.ready' &&
event.data.type === 'text' &&
event.data.language_code === 'en') {
const assetId = event.data.asset_id;
try {
// Translate to Spanish
const result = await translateCaptions(assetId, "en", "es");
console.log(`Spanish captions created: ${result.uploadedTrackId}`);
res.status(200).json({ success: true });
} catch (error) {
console.error('Translation error:', error);
res.status(500).json({ error: error.message });
}
} else {
res.status(200).json({ message: 'Event ignored' });
}
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});Under the hood, @mux/ai handles: