Edit an existing caption track on a Mux asset with the Mux Robots API. Use find-and-replace rules to fix terms, or censor profanity with an LLM.
Edit an existing text track on a Mux asset. The workflow supports three kinds of edits — static word/phrase replacements, speaker label renames via speaker_replacements, and LLM-driven profanity censoring via auto_censor_profanity — and you can combine them in a single job. By default the edited captions replace the original track, keeping its name. See Managing existing tracks. See the Edit Captions API referenceAPI for the full endpoint specification. See Mux Robots pricing for unit costs.
Caption editing requires an existing, ready text track on the asset. Add captions first, either auto-generated or manually added, before creating an edit-captions job. You must provide at least one of replacements, speaker_replacements, or auto_censor_profanity.
edit-captions jobcurl https://api.mux.com/robots/v0/jobs/edit-captions \
-H "Content-Type: application/json" \
-X POST \
-d '{
"parameters": {
"asset_id": "YOUR_ASSET_ID",
"track_id": "YOUR_TRACK_ID",
"replacements": [
{ "find": "Mucks", "replace": "Mux", "case_sensitive": true },
{ "find": "gonna", "replace": "going to" }
],
"auto_censor_profanity": {
"mode": "blank"
}
}
}' \
-u ${MUX_TOKEN_ID}:${MUX_TOKEN_SECRET}This request is asynchronous. The POST returns immediately with the job in pending status and does not include results. We strongly recommend listening for the robots.job.edit_captions.completed webhook — the payload contains the full completed job, so no follow-up API call is needed. If webhooks aren't an option, you can poll GET /robots/v0/jobs/edit-captions/{JOB_ID} with the id from the response until the status is completed.
| Parameter | Type | Description |
|---|---|---|
asset_id | string | Required. The Mux asset ID whose text track will be edited. |
track_id | string | Required. The existing, ready Mux text track ID to edit. |
replacements | array | Static find/replace rules applied to cue text. See Replacements below. |
speaker_replacements | array | Renames the bracketed speaker labels at the start of cues. See Speaker replacements below. |
auto_censor_profanity | object | LLM-driven profanity detection and censorship rules. See Auto-censor profanity below. |
upload_to_mux | boolean | Whether to upload the edited VTT back to the asset as a text track. Defaults to true. |
replace_existing_tracks | string | What to do with the source track: replace (the default) or fail. See Managing existing tracks. |
track_name | string | Name for the edited text track. Defaults to the source track's name. Required when replace_existing_tracks is fail. |
delete_original_track | boolean | Deprecated. Use replace_existing_tracks instead. Selects the previous behavior: the edit is added as {source name} ({track_name_suffix}), then the source is deleted if this is true. Can't be combined with replace_existing_tracks or track_name. |
track_name_suffix | string | Deprecated. Use track_name instead. Selects the previous naming scheme. Defaults to edited. Can't be combined with replace_existing_tracks or track_name. |
Each entry in replacements is applied to every cue in the source track.
| Field | Type | Description |
|---|---|---|
find | string | Required. Exact word or phrase to match in cue text. |
replace | string | Required. Text to insert when a match is found. Use an empty string to delete the match. |
case_sensitive | boolean | When true, find only matches with exact case. Defaults to false, so gonna also matches Gonna and GONNA. |
Use speaker_replacements to rename speakers, for example in captions generated by generate premium captions with include_speakers. Each entry renames a bracketed label at the start of a cue. Spoken text that contains the same words isn't changed.
| Field | Type | Description |
|---|---|---|
find | string | Required. The current speaker label, without the square brackets. Must match the label in the track exactly. |
replace | string | Required. The new speaker label, without the square brackets. |
Labels can't contain square brackets or line breaks.
{
"speaker_replacements": [
{ "find": "speaker_0", "replace": "Alice" },
{ "find": "speaker_1", "replace": "Bob" }
]
}Use auto_censor_profanity to detect and replace profane terms automatically.
| Field | Type | Description |
|---|---|---|
mode | string | Replacement strategy: blank (bracketed underscores, e.g. [____]), remove (drop the match entirely), or mask (replace characters with question marks). Defaults to blank. |
always_censor | array of strings | Words or short phrases that should always be censored, even if the model doesn't flag them. |
never_censor | array of strings | Words or short phrases that should never be censored, even if the model flags them. |
The outputs object is included once the job's status is completed. You'll receive it on the robots.job.edit_captions.completed webhook (recommended), or you can fetch it with GET /robots/v0/jobs/edit-captions/{JOB_ID}. It contains:
| Field | Type | Description |
|---|---|---|
total_replacement_count | integer | Total number of cue text replacements applied across all edit operations. |
uploaded_track_id | string | Mux text track ID for the uploaded edited captions. Present when upload_to_mux is true and the upload succeeds. |
temporary_vtt_url | string | Temporary pre-signed URL to download the edited VTT file. The URL expires 7 days after the job completes. |
replaced_tracks | array of objects | Every track deleted before the edited track was added. Absent when nothing was deleted. See Managing existing tracks. |
This is the payload delivered to the robots.job.edit_captions.completed webhook, and the same shape you get from GET /robots/v0/jobs/edit-captions/{JOB_ID}:
{
"data": {
"id": "rjob_example123",
"workflow": "edit-captions",
"status": "completed",
"units_consumed": 1,
"parameters": {
"asset_id": "mux_asset_123abc",
"track_id": "text_track_456def",
"replacements": [
{ "find": "Mucks", "replace": "Mux", "case_sensitive": true },
{ "find": "gonna", "replace": "going to" }
],
"upload_to_mux": true,
"replace_existing_tracks": "replace"
},
"outputs": {
"total_replacement_count": 5,
"uploaded_track_id": "text_track_789ghi",
"temporary_vtt_url": "https://s3.example.com/edited.vtt?sig=abc",
"replaced_tracks": [
{
"id": "text_track_456def",
"type": "text",
"name": "English",
"language_code": "en",
"text_source": "uploaded"
}
]
}
}
}When upload_to_mux is true (the default), the edited caption track is attached to your asset. By default it replaces the original, so viewers see the corrected captions in the player's caption menu.
Use replace_existing_tracks to choose what happens to the source track when the edit is uploaded.
| Value | Behavior |
|---|---|
replace (default) | The source track is deleted and the edited track takes its place, with the same name, language, and closed-captions setting. |
fail | Nothing is deleted. The edited track is added alongside the source, so it needs a track_name different from the source's. |
replace requires upload_to_mux to be true.replace, if the edited track can't be added, Mux attempts to restore the source under a new track ID and the job errors. Restoration is best-effort and can also fail.outputs.replaced_tracks.422. If a conflicting track is added while the job runs, the job errors instead. Neither case is billed.