---
title: Make a thumbnail for the video
description: A YouTube thumbnail from a frame of your video: a cutout of you, a bold title and a clean background, in 16:9, with variants to test.
---
You get a thumbnail, also called a cover image or YouTube thumbnail, for your video. It starts from a real frame of your video, or a shot your agent generates. Your face or the subject is cut out, a clean background goes behind it, and a short title in big letters sits on top.

Use invideo for this when the thumbnail should match the video: your agent grabs the frame from the same timeline, builds the thumbnail on its own timeline, and makes a new variant with one text change.

## Quickest path

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

```text
Make a YouTube thumbnail for my video in this project. Find the frame
where my face looks the most surprised, cut me out, put me on the
right over a bright blurred background, and add "I TRIED IT FOR 30
DAYS" on the left in big yellow letters. 16:9. Make two variants.
```

In a chat app, you look at the thumbnail in invideo and ask for changes in the chat. In a terminal, the agent saves the image to a folder you name.

## What you need

Big faces and few words read best at the small size people see in a feed.

- **The video, or a photo.** The timeline or the source clip in the project, or a photo you bring in.
- **The moment.** A time, or a description: "my reaction at the end", "the finished build".
- **The title.** Three to five words. It should add to the video title, not repeat it.
- **The look.** Colors, font, and your channel's style. Your brand guide, if you have one.
- **The shape.** 16:9, the shape YouTube shows thumbnails in.

## Steps

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

### Make the parts

The agent makes the still, the cutout and the background first.

<Steps>
<Step title="Find the frame">
The agent looks at the video with `capture` on the timeline, or `media` with `video.frames` on a source clip, at the moments you named. You pick one, or the agent picks the clearest face. Expected result: a few frames to pick from.
</Step>
<Step title="Grab the still">
From a source clip, the agent runs `media` with `video.extractFrameAtTime` on the clip's sequence URL from `add_media`, with `time_seconds` and an `idempotency_key`. From the timeline, it runs `export` with `mode` image and `still_at`. Expected result: a still image as a new sequence.
</Step>
<Step title="Cut out the subject">
The agent runs `media` with `image.removeBackground` on the still's sequence URL, `dry_run` first, and tells you the price. Then it runs it with `max_credits` and an `idempotency_key`. Expected result: a cutout of you or the subject, as a new image.
</Step>
<Step title="Make the background">
The agent runs `find_models` with `output` image and the background in words. A good pick is `flux_3_image.generate`, with a `prompt` and `aspect_ratio` 16:9. To keep the same scene, `flux_3_image.edit` takes your still in `images`. Your agent can search for others with `find_models`. The agent reads its pick with `get_model`, 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 result with `read`, never with a second `generate`. For a crisp result, it runs `media` with `image.upscale` on the image's sequence URL, `dry_run` first. Expected result: a sequence URL for a 16:9 background.
</Step>
</Steps>

### Build and export

Then the agent builds the thumbnail, makes variants and checks them small.

<Steps>
<Step title="Build the thumbnail on a timeline">
The agent makes a 16:9 timeline with `new_timeline` and a branch with `timeline_history`. It places the background on `V1` and the cutout on `V2` with `insert_media`, then moves and sizes the cutout with `set_position` and `set_zoom`. It adds `drop_shadow` to the cutout with `add_effect`. Expected result: you over the background, on one side.
</Step>
<Step title="Add the title">
The agent adds the title with `add_text`, big and bold, with `stroke` and `shadow` on. It colors one word with `style_text_range`. Expected result: a title you can read at a glance.
</Step>
<Step title="Make variants">
The agent copies the thumbnail timeline with `duplicate_timeline` for each variant. It changes the words with `set_text`, or the color with `set_text_style`. Expected result: one timeline per variant.
</Step>
<Step title="Check each variant small before export">
The agent runs `capture` on each variant and looks at it at a small size, as it shows in a feed. Expected result: a title you can read at feed size on every variant.
</Step>
<Step title="Export the stills">
The agent runs `export` with `mode` image and `still_at` for each variant, with its `timeline_id`. Expected result: one still image per variant.
</Step>
</Steps>

The same job from a terminal:

```bash
invideo agent register <project-url> --name <name>
export INVIDEO_AS=<name>
invideo edit new <project-url> --name "Thumbnail"
invideo asset upload <edit-url> ./video.mp4
invideo media video.frames <sequence-url> --at 212,214,216 --out ./pick
invideo media video.extractFrameAtTime <sequence-url> --time-seconds 214 \
  --idempotency-key thumb-still-1
invideo media image.removeBackground <still-url> --dry-run
invideo media image.removeBackground <still-url> --max-credits <price> \
  --idempotency-key thumb-cutout-1
invideo gen models <project-url> --query "bright blurred studio background"
invideo gen model <project-url> --model flux_3_image.generate
invideo gen run <page-url> --model flux_3_image.generate --dry-run \
  -i prompt="bright yellow and blue blurred studio, soft light" \
  -i aspect_ratio=16:9
invideo gen run <page-url> --model flux_3_image.generate \
  --max-credits <price> --idempotency-key thumb-bg-1 \
  -i prompt="bright yellow and blue blurred studio, soft light" \
  -i aspect_ratio=16:9
invideo status <thread-url> --wait
invideo notebook show <thread-url>
invideo media image.upscale <background-url> --dry-run
invideo media image.upscale <background-url> --max-credits <price> \
  --idempotency-key thumb-bg-up-1
invideo edit show <edit-url> --json
invideo branch new <edit-url> --name thumb-a --token <state_token>
invideo edit show <branch-url> --json
invideo edit change <branch-url> --timeline T1 \
  --token <state_token> --operations @thumb.json
invideo edit capture <branch-url> --at 0.5 --out ./thumb
invideo edit export <branch-url> --format video --mode image \
  --still-at 0.5 --json
invideo status <card-url> --wait
invideo notebook show <card-url> --out ./out
```

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>` is your video's project, from `invideo project new` or the editor. `<edit-url>` comes from `invideo edit new`.
- `<sequence-url>` is the video's `url` that `invideo asset upload` returns, a `…/notebook/seq-N.M` URL. File-making ops like `video.extractFrameAtTime` refuse a bin `--asset`.
- `<still-url>` is the sequence URL `video.extractFrameAtTime` returns. The cutout's sequence URL comes back from `image.removeBackground`.
- `<page-url>` is a notebook page of the project, listed by `invideo notebook show <project-url>`. `<price>` is each dry run's `.estimated_credits`.
- `<thread-url>` is the `url` the paid `gen run` returns. `<background-url>` is the image's sequence URL, which `invideo notebook show <thread-url>` lists.
- `<state_token>` comes from `invideo edit show`: on `<edit-url>` for the branch, then on `<branch-url>` for the change. `<branch-url>` is the `.branch_url` that `invideo branch new` returns.
- `@thumb.json` reads a bare JSON list of ops, the `operations` list of the call below. The background and the cutout are already placed with `insert_media` in an earlier change.
- `<card-url>` is `.sequences[0]` of the export result. `invideo status` waits but saves nothing. `invideo notebook show` saves the still in `./out`, and the agent renames it.

The key MCP call, shown as the full call, places the cutout, adds its shadow and the title. `<branch-url>` is the branch URL `timeline_history` returns, and `<state_token>` comes from `get_timeline` on it. `c2` is the cutout clip's id, read with `get_timeline` after `insert_media` placed it.

```json
{
  "url": "<branch-url>",
  "timeline_id": "T1",
  "expected_state_token": "<state_token>",
  "operations": [
    { "op": "set_position", "clip": "c2", "x": 480, "y": 60 },
    { "op": "set_zoom", "clip": "c2", "x": 1.2, "y": 1.2 },
    { "op": "add_effect", "clip": "c2", "effect": "drop_shadow" },
    { "op": "add_text", "track": "V3", "start_f": 0, "end_f": 30,
      "text": "I TRIED IT\nFOR 30 DAYS",
      "style": { "font_size": 180, "font_weight": 900,
                 "color": "#ffe600", "align": "left",
                 "stroke": true, "stroke_color": "#000000",
                 "stroke_width": 10, "shadow": true } }
  ]
}
```

The `export` call for the still, with `still_at` inside the text clip's time, on the same `<branch-url>`:

```json
{
  "url": "<branch-url>",
  "format": "video",
  "options": { "mode": "image", "still_at": 0.5 },
  "idempotency_key": "thumb-variant-a"
}
```

## 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.

- **Costs credits:** the cutout with `image.removeBackground`, the generated background, and `image.upscale`.
- **Tool ops:** `video.frames`, `video.extractFrameAtTime`. The dry run shows its price before anything starts.
- **Free:** finding the frame with `capture`, the thumbnail timeline, the text, the variants and the still export.

A thumbnail takes the agent a few minutes. Each variant after the first takes less. See [Credits and what they cost](/account/credits) for prices.

## If something goes wrong

Most problems come from text that is too small, or a cutout with rough edges.

| 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. |
| `video.extractFrameAtTime` or `image.removeBackground` refused with `code: "not_found"` | The call named a media bin asset. Pass the file'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>`. |
| The title is hard to read small | Use fewer words, a bigger `font_size`, and `stroke` on. Then `capture` again. |
| The cutout has a rough edge | Run `image.removeBackground` again with `model` set to the other one, `birefnet_bg_remove`. |
| The face is blurry | Pick a sharper frame, or run `image.upscale` on the still before the cutout. |
| The background has text or a logo in it | Generate it again with "no text" in the prompt. |
| The still export is blank | `still_at` is outside the clips. Set it inside the span of every clip. |
| `generate` refused for `max_credits` | The price is above the cap. Run the dry run again and agree a new cap. |
| Avoid: a frame grab of the whole video as the thumbnail | Instead: a cutout, a clean background and a few big words. |

## Prompts to try

Each prompt is a real variation of the job.

```text
Make a thumbnail from the finished build at the end of my video. Put
"BEFORE" and "AFTER" on two halves, with a red arrow between them.
```

```text
I have no good frame. Generate a photo of a person shocked at a laptop,
in my channel colors, and add "STOP DOING THIS" in big white letters.
```

```text
Make three thumbnail variants with different titles from this list,
./titles.txt, and export each as a still.
```

## When to use something else

invideo does not upload thumbnails to YouTube or test them against each other. Upload the stills in YouTube Studio, and use its own test tools there.

For a detailed design with many layers and photo retouching, use an image editor like Photoshop, Canva or Figma. Bring the finished image back in with `add_media` if you want it in the video.

## Related

- [Make a faceless YouTube video yourself, with AI help](/how-to/creators/faceless-youtube-video)
- [Edit a long YouTube video](/how-to/creators/edit-a-long-youtube-video)
- [Make an intro, welcome video, outro or logo animation for your channel or business](/how-to/creators/intro-outro-logo-animation)
- [Models](/reference/models)
- [Check your video before you say it is done](/how-to/check-your-video)