---
title: Resize one master ad for every placement, with safe zones
description: Resize one master ad to every aspect ratio and placement, with safe zone guides, text moved per size, and one named export each.
---
Resize one master ad for every placement: 9:16 for Reels, Stories, TikTok and Shorts, 4:5 and 1:1 for feeds, and 16:9 for YouTube. Your agent copies the master once per aspect ratio, reframes each shot so faces and the product stay in frame, draws the platform's safe zones as guides, moves the text inside them, and exports one named file per size.

This is ordinary ad work for a real product. The agent makes the files. You upload them to each ad platform and switch them on. The agent never publishes an ad.

Use invideo for this when you want every size to stay an editable timeline beside the master, so a change to the copy or a shot is a few edits in each size and a free export.

## Quickest path

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

```text
Make 9:16, 4:5, 1:1 and 16:9 versions of this ad: <edit-url>.
Keep faces and the product in frame, add safe zone guides for Reels and
TikTok from their spec pages, move the text inside them, and export each
size named ad7_9x16_v1, ad7_4x5_v1 and so on. Show me frames of each
size before you export.
```

Replace `<edit-url>` with the master's timeline URL, from the editor's address bar. In a chat app, you paste the timeline URL. In a terminal, the agent finds it with `invideo project show` and saves the frames to a folder.

## What you need

The agent needs the master and the list of sizes.

- The timeline URL of the master ad, cut and approved.
- The placements, and the size for each. Common canvases are 1080 by 1920 for 9:16, 1080 by 1350 for 4:5, 1080 by 1080 for 1:1 and 1920 by 1080 for 16:9.
- The safe zone for each placement, from the platform's own page.
- Your naming scheme for the files.

## Safe zones in words

A safe zone is the part of the frame that the app's buttons, captions and profile name do not cover. Each platform publishes its own, and it changes, so the agent reads the page on the day.

- **Meta Reels and Stories.** Keep text, logos and faces off the top, bottom and side edges of a 9:16 ad. With a disclaimer on a Reels ad, Meta asks for more room at the bottom. See <a href="https://www.facebook.com/business/help/980593475366490" target="_blank">About text overlays and the safe zone for ads in Stories and Reels</a> and <a href="https://www.facebook.com/business/help/103816146375741" target="_blank">Best practices for aspect ratios</a>.
- **TikTok.** The safe zone depends on the orientation and on how long the caption is. TikTok gives safe zone files to download on <a href="https://ads.tiktok.com/help/article/tiktok-auction-in-feed-ads" target="_blank">TikTok Auction In-Feed Ads</a>.
- **YouTube Shorts.** Google recommends 9:16 vertical video and describes the buttons on the right of the Shorts player on <a href="https://support.google.com/google-ads/answer/16041697" target="_blank">YouTube Shorts ads: asset specs and best practices</a>.

## Steps

The agent leaves the master alone and works on copies.

<Steps>
<Step title="Copy the master once per size">
The agent reads the master with `get_timeline`, then runs `duplicate_timeline` once per size, named like ad7_9x16_v1. It sees one new timeline id per size.
</Step>
<Step title="Set each canvas">
The agent runs `set_timeline_settings` on each copy with the width, height and the master's `fps`. It sees the new canvas in `get_timeline`, with the clips now too wide or too tall.
</Step>
<Step title="Reframe each shot">
For each clip, the agent runs `fill_frame`, then moves the picture with `set_position` so the face or the product sits in the center of the safe area. It uses `set_zoom` where a shot needs to be tighter. It sees each clip's new position.
</Step>
<Step title="Generate fill for a shot that cannot be cropped">
The agent runs `find_models` with the job in words, picks one, and reads its inputs with `get_model`. A good pick is `ltx_2_3_pro.reframe`, which fills the new space with generated picture. It calls `generate` with `dry_run: true`, the shot's sequence URL as `video` and the new `aspect_ratio`, and tells you the price. Then it calls `generate` with `max_credits` set to that price and an `idempotency_key`. It sees a new sequence URL, reads it with `read`, and places that shot over the clip with `place_media`.
</Step>
<Step title="Draw the safe zone">
The agent adds the safe zone with `create_guide`: horizontal guides for the top and bottom bands and vertical guides for the sides, each a fraction of the canvas. It locks them with `locked`, so nobody drags them by mistake. It sees the guides in `get_timeline` mode `collection`.
</Step>
<Step title="Move the text inside the guides">
The agent moves each text clip with `set_position` and resizes it with `set_text_style`. It copies one clip's place to the others with `paste_attributes` and `transform`. It sees the text inside the guides.
</Step>
<Step title="Check each size, then export">
The agent calls `capture` on each copy at the hook, each text and the end card, and runs `check_timeline`. Then it runs `export` once per copy with `timeline_id`. It sees one export card per size with status `completed`.
</Step>
</Steps>

The terminal version, for the 9:16 copy:

```bash
invideo agent register <project-url> --name <name>
export INVIDEO_AS=<name>
invideo edit show <edit-url> --json
invideo edit change <edit-url> --timeline T1 --token <state_token> \
  --operations @copies.json
invideo edit show <edit-url> --json
invideo edit change <edit-url> --timeline T2 --token <state_token> \
  --operations @9x16.json
invideo gen models <project-url> --query "reframe a shot to a new shape"
invideo gen model <project-url> --model ltx_2_3_pro.reframe
invideo gen run <page-url> --model ltx_2_3_pro.reframe --dry-run \
  -i video=<sequence-url> -i aspect_ratio=9:16
invideo gen run <page-url> --model ltx_2_3_pro.reframe \
  --max-credits <price> --idempotency-key ad7-c5-9x16 \
  -i video=<sequence-url> -i aspect_ratio=9:16
invideo edit capture <edit-url> --timeline T2 --at 0.5,4,9,14 \
  --out ./frames/9x16
invideo edit check <edit-url>
invideo edit export <edit-url> --format video --quality 1080 \
  --timeline T2 --json
invideo status <card-url> --wait
invideo notebook show <card-url> --out ./9x16
mv ./9x16/export.mp4 ./9x16/ad7_9x16_v1.mp4
```

Where the values come from:

- `<edit-url>` is the master's timeline URL, and `<project-url>` is the project it sits in, from `invideo project show`. `<name>` is the name you choose in `invideo agent register`. `<page-url>` is a notebook page from `invideo notebook show <project-url>`.
- `<state_token>` comes from the `invideo edit show` right before each change. After the copies land, the first token is stale.
- `T2` is the 9:16 copy's id, from what `duplicate_timeline` returns or `invideo edit show`.
- `<sequence-url>` is the sequence URL of the shot that cannot be cropped, from `invideo notebook show <project-url>`. `<price>` is the dry run's `.estimated_credits`.
- `<card-url>` is `.sequences[0]` of what the export returns. `invideo status` waits and does not download; `invideo notebook show` saves `./9x16/export.mp4`.

The file `./9x16.json` holds the 9:16 copy as a bare list of operations. On the MCP path, the same list goes in the `operations` field of `edit_timeline`. The clip ids come from `get_timeline` on the copy. The guide positions are an example; take the real ones from the platform's page.

```json
[
  { "op": "set_timeline_settings", "timeline": "T2",
    "width": 1080, "height": 1920, "fps": 30 },
  { "op": "fill_frame", "clip": "c3" },
  { "op": "set_position", "clip": "c3", "x": -120, "y": 0 },
  { "op": "create_guide", "timeline": "T2", "orientation": "horizontal",
    "position": 0.14, "locked": true },
  { "op": "create_guide", "timeline": "T2", "orientation": "horizontal",
    "position": 0.65, "locked": true },
  { "op": "create_guide", "timeline": "T2", "orientation": "vertical",
    "position": 0.06, "locked": true },
  { "op": "create_guide", "timeline": "T2", "orientation": "vertical",
    "position": 0.94, "locked": true },
  { "op": "set_position", "clip": "c9", "x": 0, "y": -300 }
]
```

## 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: `ltx_2_3_pro.reframe` on a shot that needs generated fill. It charges by the length of the source.
- Free: the copies, the canvas, `fill_frame`, `set_position`, `set_zoom`, guides, `capture` and every `export`.

All the sizes take under an hour by hand. See [Credits](/account/credits) for prices.

## If something goes wrong

Most problems are a cropped face or text under the buttons.

| 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. |
| You want branches instead of copies | Create one branch per size with `timeline_history` instead of `duplicate_timeline`. |
| A face is cut at the edge in 9:16 | Move the clip with `set_position`, or lower the zoom with `set_zoom`, and capture again. |
| `fill_frame` refused | The clip's zoom is animated. Remove the zoom animation first, or move it by hand. |
| The product leaves the frame halfway through the shot | One position does not fit a moving shot. Split the clip with `split_clip` and position each part, or use `ltx_2_3_pro.reframe`. |
| Black bars in the export | A clip is fit, not filled. Run `fill_frame` on it. |
| Lines show in a capture or the export | Check with `get_timeline` whether they are guides or a shape clip. Remove guides with `delete_guide` before the export, and file `report_bug`. |
| CLI exit 3 | The edit changed since your read. Run `invideo edit show` and use its new `state_token`. |
| The saved file is called `./9x16/export.mp4` | `notebook show` always saves `./9x16/export.mp4`. Rename it to your scheme. |
| Avoid: one guide set for every platform | Instead: one set per placement, from that platform's page. |
| Avoid: resizing the master | Instead: `duplicate_timeline`, and resize the copy. |

## Prompts to try

Each prompt is a real variation of this job.

```text
The 16:9 master is done. Make only the 9:16 version for TikTok, with
TikTok's safe zone for a two-line caption, and export it.
```

```text
The headline changed. Change it in the master and in all four sizes, keep
each size's position, and export version 2 of each.
```

```text
Shot 3 loses the product in 1:1. Price a generative reframe of that shot
only, and wait for my OK.
```

## When to use something else

`ltx_2_3_pro.reframe` fills new space with generated picture. It is not a face-tracking crop. For an automatic crop that follows a face through a long shot, a tool with face tracking, like Auto Reframe in Premiere Pro or Smart Reframe in DaVinci Resolve, fits better. Each platform's ad preview is the final check of the safe zone.

## Related

- [Repurpose for every platform](/how-to/creators/repurpose-for-every-platform)
- [Make performance ads for Meta, TikTok and YouTube, named and iterated from results](/how-to/marketing/performance-ads)
- [Make static ads at volume from the same brief as your video ads](/how-to/marketing/static-ads-at-volume)
- [Check your video before you say it is done](/how-to/check-your-video)
- [Timeline edit operations](/reference/edit-operations)