---
title: Edit a long YouTube video: cut the dead parts, add b-roll, music and captions
description: Edit your long YouTube recording: cut the dead air and ums, add b-roll over the talk, music under it, captions, chapters and a thumbnail still.
---
You get your long YouTube recording edited into a video people watch to the end. The dead air, ums and false starts are cut, b-roll covers the long talking stretches, music runs under your voice and dips when you talk, captions are on, chapters are marked, and you get a still for the thumbnail.

Use invideo for this when you want an editor that reads your whole recording: your agent works from a transcript of every word, makes each change on a branch, and you can review and undo any cut on the timeline.

## Quickest path

Set up your agent first with [invideo for AI agents](/agents). Then give it this prompt.

```text
Edit my YouTube video ./episode-12.mp4 on a branch. Cut dead air and
ums, add stock b-roll over long talking parts, calm music ducked under
my voice, and captions. Mark chapters and give me the chapter list.
Price the transcript and stock first, and show me frames before export.
```

In a chat app, you drag the recording into the project's Media panel in invideo. In a terminal, you name the file and the agent uploads it, which works for large files.

## What you need

Your recording is the main input. The rest shapes the edit.

- **The recording.** The full take from your camera or screen recorder, MP4 or MOV, as large as it is.
- **Your own b-roll, if you have it.** Clips of the product, the place, your screen.
- **The music or the mood.** Stock, generated, or your own track.
- **The caption look.** Or no captions.
- **What must stay.** Jokes, a sponsor read, a call to action.

## Steps

Your agent edits on a branch and tells you what changed at each step.

<Steps>
<Step title="Upload the recording">
The agent calls `start_upload` with the `file_name`, sends the bytes with one PUT to the `upload_url`, then calls `add_media` with the `upload_id` and the timeline URL. Expected result: a sequence URL and a media bin id.
</Step>
<Step title="Lay it out on a branch">
The agent makes a 16:9 timeline with `new_timeline`, creates a branch with `timeline_history`, saves a `checkpoint` on it, and places the recording with `place_media` and `linked_audio` true. Expected result: the recording on the timeline, with its sound.
</Step>
<Step title="Transcribe and cut the dead parts">
The agent prices `media` `audio.transcript` with `dry_run` on the recording's sequence URL from `add_media`, starts it with `max_credits`, and calls again after `retry_after_s` for the words. It runs `audio.content` for the silent spans. It shows you a cut list of pauses, ums and false starts. Once you approve, it cuts each span with `edit_time_range` in `close_gap` mode, from the last to the first. Expected result: a tighter cut on the branch.
</Step>
<Step title="Add b-roll over the talk">
The agent reads the transcript for long stretches on one topic. It searches `stock_video` with `search_library` using the words you say there, and adds your picks with `add_media` and `stock`. It places each one on a track above with `place_media` in `place_on_top` mode and `linked_audio` false, so your voice keeps playing. For a shot stock does not have, it runs `find_models` with the shot in words and reads its pick with `get_model`. A good pick is `seedance_2_5.r2v`, where a `prompt` alone is enough. Your agent can search for others with `find_models`. It calls `generate` with `dry_run: true` and tells you the price. For a price of 1 credit or more it waits for your yes. Then it calls `generate` with `max_credits` set to that price and an `idempotency_key`. Expected result: b-roll over the talking parts, your voice under it, and a sequence URL for each generated shot, read with `read`.
</Step>
<Step title="Add music under the voice">
The agent adds a stock track from `stock_music`. For music made to the episode's length, it runs `find_models` with "instrumental music bed" and reads its pick with `get_model`. A good pick is `elevenlabs_music_v2_5_instrumental`. It calls `generate` with `dry_run: true` and tells you the price. For a price of 1 credit or more it waits for your yes. Then it calls `generate` with `max_credits` set to that price and an `idempotency_key`, and reads the sequence URL with `read`. It places the track with `insert_media` on its own audio track, and sets its level with `set_audio_gain`. It adds the `ducker` to the music track with `add_audio_effect`. A new timeline ducks under `A1` by default, so the agent sets `set_sidechain_source` only when your voice is on another track. Expected result: music that dips when you talk.
</Step>
<Step title="Add captions and chapters">
The agent adds captions with `add_captions` from the transcript's word times. It marks each topic change with `add_marker` and a `name`, then writes the chapter list with timecodes for your YouTube description. Expected result: captions on the timeline, and a chapter list you can paste.
</Step>
<Step title="Check, export, and make a thumbnail still">
The agent runs `capture` at the start, a few cuts, the b-roll and the end, and runs `check_timeline`. Then it runs `export` with `format` video and a `target_lufs` for YouTube, and a second `export` with `mode` image and `still_at` the frame you want for the thumbnail. Expected result: a 1080p MP4 and a still image, each on a card with status `completed`.
</Step>
</Steps>

The same job from a terminal:

```bash
invideo project new --title "Episode 12"
invideo agent register <project-url> --name <name>
export INVIDEO_AS=<name>
invideo edit new <project-url> --name "Episode 12"
invideo asset upload <edit-url> ./episode-12.mp4
invideo edit show <edit-url> --json
invideo branch new <edit-url> --name first-cut --token <state_token>
invideo media audio.transcript <sequence-url> --dry-run
invideo media audio.transcript <sequence-url> \
  --max-credits <price>
invideo media audio.content <branch-url> --asset m1
invideo library search <project-url> --library stock_video \
  --query "coffee beans roasting"
invideo asset add <branch-url> --stock <id>
invideo gen models <project-url> --query "b-roll shot from a prompt"
invideo gen model <project-url> --model seedance_2_5.r2v
invideo gen run <page-url> --model seedance_2_5.r2v --dry-run \
  -i prompt="close up of coffee beans tumbling in a roaster"
invideo gen run <page-url> --model seedance_2_5.r2v \
  --max-credits <price> --idempotency-key broll-roast \
  -i prompt="close up of coffee beans tumbling in a roaster"
invideo status <thread-url> --wait
invideo edit show <branch-url> --json
invideo edit change <branch-url> --timeline T1 \
  --token <state_token> --operations @ops.json
invideo edit capture <branch-url> --at 0,60,300,900 --out ./frames
invideo edit check <branch-url>
invideo edit export <branch-url> --format video --quality 1080 \
  --target-lufs -14 --json
invideo status <card-url> --wait
invideo notebook show <card-url> --out ./out
invideo edit export <branch-url> --format video --mode image \
  --still-at 312 --json
invideo status <card-url> --wait
invideo notebook show <card-url> --out ./out/still
```

Where each value comes from:

- `<name>` is the name you choose in `invideo agent register`. `INVIDEO_AS` passes it to every later command.
- `<project-url>` comes from `invideo project new`, and `<edit-url>` from `invideo edit new`.
- `<sequence-url>` is the `url` that `invideo asset upload` returns. `m1` is the recording's bin id from the same result, and works for reads like `audio.content`. A transcript refuses `--asset`.
- `<state_token>` comes from `invideo edit show <edit-url>` for the branch command. `<branch-url>` is the `.branch_url` that `invideo branch new` returns. For `edit change`, `<state_token>` is read again with `invideo edit show <branch-url>`. The main token is stale on the branch.
- `<price>` is each dry run's `.estimated_credits`. `<id>` is a stock result's id from `invideo library search`.
- `<page-url>` is a notebook page of the project, listed by `invideo notebook show <project-url>`. `<thread-url>` is the `url` the paid `gen run` returns.
- `@ops.json` reads a bare JSON list of ops, the `operations` list of the call below.
- `<card-url>` is `.sequences[0]` of each export result, one for the video and one for the still. `invideo status` waits but saves nothing. `invideo notebook show` saves the files, the video as `./out/export.mp4`, and the agent renames them.

The key MCP call puts one b-roll shot over the talk, marks a chapter and ducks the music under `A1`, the default source on a new timeline. This is the full call. `<branch-url>` is the branch URL that `timeline_history` returns, and `<state_token>` comes from `get_timeline` on it. `m4` is the b-roll's bin id, from the `add_media` result. At 30 fps, 4 minutes 10 seconds is frame 7500.

```json
{
  "url": "<branch-url>",
  "timeline_id": "T1",
  "expected_state_token": "<state_token>",
  "operations": [
    { "op": "place_media", "asset": "m4", "track": "V2", "at_f": 7500,
      "source_start_seconds": 2.0, "source_end_seconds": 8.0,
      "mode": "place_on_top", "linked_audio": false },
    { "op": "add_marker", "at_f": 7440, "name": "Roasting",
      "color": "#ffd23f" },
    { "op": "add_audio_effect", "target": "A2",
      "target_kind": "track", "effect": "ducker" }
  ]
}
```

## Cost and time

Edits and exports are free. Generation and transcripts cost credits. Paid stock costs a small credit charge, or one of your workspace's iStock licenses. Your agent runs a dry run first and tells you the price before it spends anything.

- **Free:** the upload, every cut, your own b-roll, captions, markers, ducking, the export and the thumbnail still.
- **Tool ops:** `audio.content`. The dry run shows its price before anything starts.
- **Costs credits:** the transcript with `audio.transcript`, once per file, each paid stock clip and track you place, and any shot from `seedance_2_5.r2v` or track from `elevenlabs_music_v2_5_instrumental`.

A long video takes the agent longer than a Short, from a few minutes for the cuts to under an hour with b-roll picked and checked. The export of a long video takes a while; the agent follows the card and does not export again. See [Credits and what they cost](/account/credits) for prices.

## If something goes wrong

Most problems come from a big file, cuts in the wrong order, or b-roll that covers a moment you wanted on camera.

| Symptom | Fix |
| --- | --- |
| `get_model` or `generate` refuses the model as not found | Models retire. Run `find_models` with the job in words, use the best match, and tell the person which model you used. |
| Exit code 6, or `status` is `held` | A safety review, not a refusal. Wait, then run `invideo status <url> --wait` again. Do not resend. If it ends `failed`, change the input the review flagged. |
| `audio.transcript` refused with `code: "not_found"`, or CLI exit 2 | The call named a media bin asset. Pass the recording's sequence URL from `add_media` or `invideo asset upload`. |
| `invideo status --wait` ends and the folder is empty | `status` does not download. Run `invideo notebook show <card-url> --out <dir>`. |
| `add_media` with a link fails on a big file | Use `start_upload`, PUT the bytes, then `add_media` with the `upload_id`. |
| The export takes a long time | Follow the card with `read` or `invideo status --wait`. For a very long video, export in parts with `start` and `end`, then join them with `media` `video.stitch`. |
| B-roll covers a face you wanted | Move or shorten the b-roll clip with `move_clip` or `trim_clip`. |
| The b-roll has its own sound | It was placed with `linked_audio` true. Mute it with `set_audio_muted`, or place it again with `linked_audio` false. |
| Cuts land in the wrong place | They were made first to last. Restore the checkpoint and cut from last to first. |
| Chapters are off after more cuts | Markers sit at frames. The agent reads them with `get_timeline` after the last cut and writes the list again. |
| CLI exit 7 | Nothing ran. Run the same command again. |
| Avoid: running `export` again to check on a slow one | Instead: `read` the export card, or `invideo status --wait`. Pass an `idempotency_key` so a retry finds the first. |
| Avoid: editing main | Instead: work on a branch, and you accept it in the editor. |

## Prompts to try

Each prompt is a real variation of the job.

```text
Make a first cut of my two hour stream VOD for YouTube. Cut every part
where I am away or silent, keep the chat reactions, and mark a chapter
at each game change.
```

```text
Edit my tutorial ./lesson.mp4: cut the mistakes and long pauses, zoom
in on my screen when I click, captions on, no music. Give me a
thumbnail still where I show the result.
```

```text
Add b-roll from my own folder ./broll to every part where I talk about
the trip for more than 20 seconds. Use stock only where my clips do
not fit.
```

## When to use something else

invideo does not upload to YouTube or set the chapters there. Paste the chapter list into the video's description in YouTube Studio. For a designed thumbnail with big text and a cut-out face, see the thumbnail page; the still from `export` is its starting frame.

## Related

- [Cut ums, pauses and retakes, as reversible timeline edits](/how-to/creators/cut-ums-and-retakes)
- [Make a thumbnail for the video](/how-to/creators/thumbnail)
- [Add music and sound effects that clear rights](/how-to/creators/music-and-sound-effects)
- [Add word-by-word captions](/how-to/creators/word-by-word-captions)
- [Make a faceless YouTube video yourself, with AI help](/how-to/creators/faceless-youtube-video)
- [Check your video before you say it is done](/how-to/check-your-video)