Vertex Veo Remove Content
Erase anything from a video — the clean-room cleanup node
- video
- mask_image
- videos
- video_path_list
Vertex Veo Remove Content is the sibling of the Insert Content node, and it's the one ad teams probably use more. Mask an object, a person, a brand logo, a street sign, and Veo erases it from the footage - filling the hole with plausible background that moves with the scene. It's inpainting for video, and unlike still-image inpainting, "remove this from the frame" is a job that doesn't have a great local open-source answer yet.
This is the quiet node of the Adforge pack, and the one with the most telling design detail: every input is optional. Even prompt. Pure removal needs no text at all - you mask, it removes. The prompt field only gets sent to the API if you actually type something, which makes sense: removal is the rare generation task where less instruction is better, since you want the model to infer the clean background rather than invent new content.
How it works
Same skeleton as Insert Content, one parameter different: the mask goes into the config as VideoGenerationMask with mask_mode set to REMOVE instead of INSERT. You still need a video - from the video input or video_gcs_uri - and a mask - from mask_image or mask_image_gcs_uri. Both are mandatory in practice even though nothing in the schema forces them; run it without a mask and it raises a ValueError before any API call. From there it's the pack's standard pipeline: async generate_videos, polled every five seconds, output written to GCS then downloaded back. Outputs are videos (VIDEO list) and video_path_list (local paths).
The configuration surface is the shared one: model, aspect_ratio, resolution (1080p/720p, Veo 3 only), duration_seconds (1–10), fps, seed, number_of_videos (1–4), enhance_prompt, generate_audio (off by default here), person_generation, negative_prompt, plus the video_mime_type / mask_mime_type pair. Defaults are fine to start; the mask quality is where the result lives.
The trap: static mask, moving footage
This is the thing that will burn you first. A video is a stack of frames, but you give Veo one mask image - so where the object sits matters. If your object stays roughly put (a parked car, a static logo), one careful mask works. If it moves across the frame, a single mask can't follow it, and removal gets patchy or the model starts "fixing" areas you didn't mean to touch. The practical answer is to mask generously - cover the object's whole travel zone and let Veo figure out the cleanup - and accept that you may need a couple of paid takes to get a clean frame range.
Installing and authenticating
Search adforge in ComfyUI Manager, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Creditas-labs/ComfyUI-Adforge
cd ComfyUI-Adforge
pip install -r requirements.txt # or: uv sync
Restart; Python 3.12+. Auth is the same Vertex ceremony as the rest of the pack: .env in custom_nodes/comfyui_adforge/ with GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_STORAGE_BUCKET, GOOGLE_CLOUD_LOCATION, API_KEY (or exported env vars), and a real GCS bucket for output. A GOOGLE_APPLICATION_CREDENTIALS service-account JSON works in place of the API key.
Common issues
- Refusals on people. Veo is cautious about people and faces -
person_generationdefaults toallow_adult, but if you're removing a person and hitting blocks, that's the dial, and it may still refuse in borderline cases. - Resolution drift. Asking for 1080p and receiving 720p is a known Veo 3.1 quirk; the node faithfully requests what you set.
- Cost. Every take is a billed API call, and removal is fiddly enough that you'll iterate. Batch your mask variants before you start spending.
Inputs (19)
| Name | Type | Default | Description |
|---|---|---|---|
| videoopt | VIDEO | The video to process. | |
| video_gcs_uriopt | STRING | No documentation available | |
| mask_imageopt | IMAGE | The mask defining the area of interest. | |
| mask_image_gcs_uriopt | STRING | No documentation available | |
| promptopt | STRING | The text prompt used to guide video generation. | |
| negative_promptopt | STRING | Optional. A text string that describes anything you want to discourage the model from generating. | |
| output_gcs_uriopt | STRING | None/videos/video-remove-content-20260720-202149.mp4 | GCS URI where the generated videos will be stored, in the format 'gs://BUCKET_NAME/SUBDIRECTORY'. |
| modelopt | COMBO | veo-3.1-generate-preview | 7 options: veo-3.1-generate-preview, veo-3.1-fast-generate-preview, veo-3.0-generate-001, veo-3.0-fast-generate-001, veo-2.0-generate-001, veo-2.0-generate-exp, +1 |
| aspect_ratioopt | COMBO | 16:9 | 3 options: 16:9, 9:16, 1:1 |
| video_mime_typeopt | COMBO | video/mp4 | 1 options: video/mp4 |
| mask_mime_typeopt | COMBO | image/png | 2 options: image/png, image/jpeg |
| duration_secondsopt | INT | 81–10 | — |
| resolutionopt | COMBO | 1080p | 2 options: 1080p, 720p |
| fpsopt | INT | 241–60 | — |
| seedopt | INT | 00–2147483647 | — |
| number_of_videosopt | INT | 11–4 | — |
| enhance_promptopt | BOOLEAN | true | — |
| generate_audioopt | BOOLEAN | false | — |
| person_generationopt | COMBO | allow_adult | 2 options: allow_adult, dont_allow |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| videos | VIDEO | — |
| video_path_list | STRING | — |