Character Swap (Nano Banana Pro)
Put Your Character Into a Real Photo Without Rebuilding the Shot
- shot_reference
- character
- wardrobe
- IMAGE
- final_prompt
- diagnostics
You have a photo where everything is right except the person. The framing, the lens, the light, the grade, the pose - you'd keep all of it. You just want your character standing there instead.
Same-subject swaps are the hard version of that, and exactly where local instruction editors fall over: hand one two different women and nothing says which is the keeper. This node's contribution is the shape of the request that fixes it.
Two things up front: it's not local, so every image is a Google call on your own billing, and the pack is new and small with no track record yet. Read the source before your first run, like any API node that holds a key.
How it works
The request isn't one prompt followed by a pile of images. It alternates a text label and then the images that label describes - SHOT REFERENCE, CHARACTER, WARDROBE - so the model never infers roles from position. The shot-reference label is explicit that the face is the one thing you must not take from it; the character label says reproduce this identity exactly.
Second half of the trick: the request always states who to remove. remove_subject defaults to "the person currently in the shot reference", and without that line the original person survives - the model was told what to add, not what to delete. Be specific ("the blonde woman on the left").
A priority directive goes in last, where these models pay most attention: face and identity first, then your blocking and wardrobe notes, then the framing, lighting, colour, set and pose of the reference. Pose is always stated, never inferred. If blocking_notes is empty and a shot reference is connected, the node tells the model to match the reference pose - empty means keep, not guess.
aspect_ratio: auto reads the reference's shape and picks the nearest supported ratio - a 1920×802 scope frame still comes back scope-shaped. Forcing 16:9 on a wide reference re-blocks the whole composition, the usual reason a swap looks subtly wrong.
The inputs that matter
Connect shot_reference (the photo to copy), character (a clean portrait) and optionally wardrobe. That's the minimum; across those three the node caps you at 14 images, matching Google's own reference limit.
Then three text boxes do most of the work: remove_subject (who to delete), blocking_notes (empty keeps the pose; fill it, frame-relative, to change it - "she leans frame left"), and do_not. On this node do_not is empty by default, whatever the README's table says - paste the blockers yourself: no text, no watermark, no extra people, no duplicated or cloned person, no collage, no grid, no split frame, no border.
backend defaults to Vertex AI, model to gemini-3-pro-image-preview (Nano Banana Pro) and resolution to 2K - 1K/2K/4K is your cost dial, and Pro is the one that does 4K natively. seed tops out at int32 rather than ComfyUI's usual 2^64, because that's what Google's field accepts.
Three outputs: IMAGE (wire it to SaveImage or PreviewImage - not an output node), final_prompt (the readable transcript of what actually got sent) and diagnostics. Read the latter: Google happily returns HTTP 200 while quietly substituting someone else's face, so finishReason, safety flags and requested-vs-used aspect separate a bad prompt from a refusal. On a real public figure it will have steered, and no prompt works around that.
Install
Manager: search the pack title. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/haristahir1/comfyui-character-swap
There's no requirements.txt - requests/torch/numpy/Pillow are already in ComfyUI. AI Studio needs nothing else; Vertex needs google-auth, declared in pyproject.toml.
Setup
Vertex, which the pack recommends - Google excludes Gemini API on AI Studio from the $300 Cloud trial, so AI Studio credit won't pay for it:
gcloud auth login
gcloud auth application-default login # both. the second is the one Python reads
gcloud services enable aiplatform.googleapis.com --project=YOUR_PROJECT_ID
Then copy config.json.example to config.json and set vertex.project_id. AI Studio instead: put the key in config.json or GEMINI_API_KEY, never the api_key widget - widget values get saved into every workflow you export and the error reports people paste into Discord. Search anything you share for AIza first.
Where it goes wrong
429 prepayment credits depleted means the AI Studio balance is zero - top up or move to Vertex. 403 SERVICE_DISABLED means you skipped the gcloud services enable line. Vertex mode needs credentials almost always means you ran gcloud auth login and stopped there; the application-default login is the one that matters. A 404 on a Vertex model is usually the region - set "location": "us-central1" instead of "global". If a 4K Pro run ever times out, raise timeout (300s default, up to 1800).
Use one clear portrait as the character; a contact sheet returns several people.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| backend | COMBO | Vertex AI (gcloud or service account) | 2 options: AI Studio (api key), Vertex AI (gcloud or service account) |
| model | COMBO | gemini-3-pro-image-preview | 3 options: gemini-3-pro-image-preview, gemini-2.5-flash-image, gemini-2.0-flash-preview-image-generation |
| seed | INT | 420–2147483647 | — |
| aspect_ratio | COMBO | auto (match reference) | 11 options: auto (match reference), 1:1, 2:3, 3:2, 3:4, 4:3, +5 |
| resolution | COMBO | 2K | 3 options: 1K, 2K, 4K |
| shot_referenceopt | IMAGE | — | |
| characteropt | IMAGE | — | |
| wardrobeopt | IMAGE | — | |
| shot_notesopt | STRING | — | |
| remove_subjectopt | STRING | the person currently in the shot reference | — |
| character_notesopt | STRING | — | |
| wardrobe_notesopt | STRING | — | |
| blocking_notesopt | STRING | — | |
| do_notopt | STRING | — | |
| api_keyopt | STRING | — | |
| timeoutopt | INT | 30030–1800 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |
| final_prompt | STRING | — |
| diagnostics | STRING | — |