Extensions/Character Swap (Nano Banana Pro)
ComfyUI Extension

Character Swap (Nano Banana Pro)

Put your own character into any photo, keeping its framing, lighting, grade and pose. Runs Nano Banana Pro (Gemini 3 Pro Image) on your own Google billing via AI Studio or Vertex AI.

By haristahir1·Created 21 days ago·Updated 19 days ago· 1
haristahir1/comfyui-character-swap
Nodes2
On cloudLocal install
CategoryCharacter Swap
Stars1
Updated19 days ago
Readme

ComfyUI Character Swap — Nano Banana Pro on your own Google API key

Put your own character into any photo, keeping that photo's framing, lighting, colour grade and pose. Runs on Nano Banana Pro (gemini-3-pro-image-preview) and other Google Gemini image models, billed to your own Google account.

| Node | What it does | |---|---| | Character Swap (Nano Banana Pro) | Replaces the person in a reference photo with your character, keeping the original shot intact | | Read the Shot | Writes an editable breakdown of a photo — framing, lens, lighting, pose. Cheap text call |

Building a new shot out of several references instead of swapping a person into one? See Multi Reference Shot.


Why the swap holds up

Most setups send the model one prompt followed by a pile of images and hope the ordering survives. It usually doesn't. This node fixes that, and four other things that break these edits in practice.

Role labels are interleaved, not batched. Every image is sent immediately after a text label saying exactly what it is — SHOT REFERENCE, CHARACTER, WARDROBE. The model never infers roles from position.

This is what makes same-subject swaps work. Replacing a woman in a photo with a different woman fails almost everywhere else, because nothing distinguishes the two and the model keeps the one already embedded in the composition.

The original subject is removed explicitly. Every request states who to delete, not only who to add. Told only what to add, a model leaves the original in place.

Aspect ratio comes from the reference. A 1920×802 scope reference returns a 1584×672 frame. Forcing a wide reference into 16:9 re-blocks the entire composition, and it is the most common reason a swap "looks wrong" for no obvious reason.

Pose is stated, never assumed. Left unsaid, the model treats pose as free invention. When blocking_notes is empty the node instructs it to match the reference exactly, so empty means keep, not guess.

Diagnostics tell you what actually happened. finishReason, safety flags, whether the aspect was honoured. Google returns HTTP 200 even when it has quietly substituted a face, so without this a refusal is indistinguishable from a bad prompt.

Seeds are clamped to int32 as well — Vertex rejects ComfyUI's default 2^64 seeds outright.


Two backends

| Backend | Endpoint | Auth | Google Cloud $300 trial credit | |---|---|---|---| | AI Studio | generativelanguage.googleapis.com | API key | ❌ excluded by Google | | Vertex AI | aiplatform.googleapis.com | gcloud login or service account | ✅ applies |

Since March 2026 Google excludes Gemini API in AI Studio from the $300 Cloud free trial. Most Gemini nodes only talk to AI Studio, so the trial credit cannot pay for them. Vertex is the route that works.

Sources: Free Cloud features · Gemini API billing


Install

cd ComfyUI/custom_nodes
git clone https://github.com/haristahir1/comfyui-character-swap

Nothing extra for AI Studio — it uses requests, torch, numpy and Pillow, which ComfyUI already has.

For Vertex:

python_embeded\python.exe -m pip install google-auth

Restart ComfyUI.

Setup — Vertex AI (recommended)

  1. Install the Google Cloud CLI
  2. Log in. Both commands are needed — the second is the one Python reads, and it is the step everyone misses:
    gcloud auth login
    gcloud auth application-default login
    
  3. Enable the API:
    gcloud services enable aiplatform.googleapis.com --project=YOUR_PROJECT_ID
    
  4. Copy config.json.example to config.json and set your project id

Setup — AI Studio

Get a key at aistudio.google.com/app/apikey and put it in config.json:

{ "api_key": "AIza..." }

GEMINI_API_KEY and GOOGLE_API_KEY environment variables work too.


Using it

Load the photo to copy into SHOT REFERENCE, your person into CHARACTER, optionally a garment into WARDROBE, and run. A labelled workflow with a guide card on the canvas is in workflows/.

| Box | Use | |---|---| | shot_notes | Leave empty. Only fill it to change the scene. | | remove_subject | Who to delete. Be specific — "the blonde woman" beats the default. | | character_notes | Anything the portrait doesn't show. | | wardrobe_notes | Garment, colour, fabric. Naming what to remove helps as much as what to add. | | blocking_notes | Empty keeps the reference pose. Fill it to change the pose, always frame-relative. | | do_not | Pre-filled with the clone and collage blockers. Add to it per shot. |

Good to know

Use one clear portrait as the character, not a contact sheet — a grid of poses makes the model produce several people.

To change a large garment, generate the image fresh rather than repainting an existing one. Small objects swap reliably; a coat filling half the frame usually won't.

Google's models decline to reproduce real public figures and will quietly substitute someone else. This affects every Gemini node, not just this one, and no prompt works around it.


Keeping your API key private

The most common way people leak a Gemini key is pasting it into the node's api_key widget. Don't.

Put the key in config.json, never in the node. Widget values are saved inside every workflow JSON you export, and they are embedded in ComfyUI's error reports — the ones people routinely paste into GitHub issues and Discord. A key typed into the node travels with all of it. config.json is gitignored.

Or use an environment variable — GEMINI_API_KEY or GOOGLE_API_KEY keep it out of every file.

Or use Vertex, where no key is sent at all. Authentication is your gcloud login, so there is nothing to leak.

The widget shows the key in plain text, so it is visible in any screenshot of that node. Clear the box if you have ever typed one in.

Before sharing a workflow or an error report, search it for AIza and AQ. — that catches both key formats.

Restrict the key at Google's end. In the Cloud console you can limit an API key to the Generative Language API only, so a leaked key is far less useful to whoever finds it.

If a key has ever appeared in a screenshot, a shared workflow, an error report or a commit, rotate it. Deleting the post does not un-leak it.

Set a budget alert. These keys spend real money, and a leaked key on a billing-enabled project spends yours.

If you fork this

Run git log -p | grep -iE "AIza|AQ\." before your first push. Gitignore only protects files that were never committed — a key that went in once stays in the history until it is rewritten. And set your commit email to your GitHub noreply address, or your real address is embedded permanently.

Troubleshooting

| Error | Cause | |---|---| | 429 prepayment credits depleted | AI Studio balance is zero — top up, or switch to Vertex | | 403 SERVICE_DISABLED | Run the gcloud services enable step | | 403 PERMISSION_DENIED | Service account missing the Vertex AI User role | | 404 on a Vertex model | Try "location": "us-central1" instead of "global" | | Vertex mode needs credentials | You ran gcloud auth login but not gcloud auth application-default login | | IMAGE_SAFETY in diagnostics | Refused outright — change the reference or the prompt |

License

MIT — see LICENSE.