Nodes/NanoBanana FaceSwap/Nano Banana - Face Swap (Crop & Composite)
ComfyUI Node

Nano Banana - Face Swap (Crop & Composite)

The face swap that works when Nano Banana says no

By IxMxAMAR·Created 4 months ago·Updated about a month ago· 3
Nano Banana - Face Swap (Crop & Composite)
  • target_image
  • identity_1
  • identity_2
  • identity_3
  • identity_4
  • identity_5
  • identity_6
  • network
  • image
  • status
  • mask
  • debug_sheet
api_key
modelgemini-3.1-flash-image-preview
scopehead
grid_modeseparate_refs
custom_hint
safety_thresholdBLOCK_NONE
seed0
batch_axistarget
detectorauto
crop_size1024
histogram_matchfalse
feather_px24
image_size2K
color_matchtrue
grain_matchtrue
sharpness_matchtrue
composite_methodlaplacian
match_directional_lightingfalse
lab_strength0.60
grain_strength1.00
dry_runfalse
timeout_ms180000
ref_cap_px1024
auto_relax_on_refusedfalse

If you've spent an evening with Nano Banana 2's API, you know the pain: you send a target frame, a reference face, and a perfectly innocent edit request, and the model comes back with a safety refusal. Google tightened IMAGE_SAFETY and celebrity detection hard in January 2026, and the word "swap" itself is a tripwire for the classifier. This pack exists to route around that, and NanoBananaCropSwap is its escape hatch: detect the head, swap only that crop, composite it back into the frame.

The honest headline comes straight from the README, so let's get it out front: cropping fixes refusals caused by scene content - background, clothing, peripheral objects. It can actually increase refusals when the safety classifier is reacting to identity recognition itself. It is not a universal anti-refusal button. But when your whole-image attempt keeps dying on a busy background, this is the node you reach for.

How it works

Instead of sending the full frame, the node runs a head detector, crops tight, swaps the crop, and pastes it back with post-processing meant to make the seam vanish. The detector cascade is worth knowing: detector=auto tries MediaPipe (fast, CPU-only), then OpenCV YuNet (a ~1.8MB ONNX auto-downloaded to ~/.cache/nanobanana_faceswap/), then a Gemini vision bbox call as last resort. Pick one explicitly and it won't silently fall back - you get ERROR:detector_unavailable:<name> if it's missing.

The crop expansion is scope-driven: face grows the bbox 25% on each side, head goes up 60%, head+styling up 100%, so the crop carries just enough context. The fiddly part is the math, and the author deliberately does not clamp the expanded bbox to image bounds before squaring - clamping would shift the face center and make the swapped head land misaligned with the body. Out-of-bounds pixels are filled with cv2.copyMakeBorder replicate and composited back at the (possibly negative) anchor. That's the difference between "looks pasted" and "looks native."

Inputs that matter

  • api_key / model - your Gemini key (or set GEMINI_API_KEY in the environment), and which model: gemini-3.1-flash-image-preview (fast, default), gemini-3-pro-image-preview (Pro, slower, higher-res), or gemini-2.5-flash-image.
  • target_image + identity_1..identity_6 - the frame to change and up to six reference faces.
  • scope - face (eyes/nose/mouth/skin, keep hair and ears), head (adds hair + ears), head+styling (adds jewelry and makeup).
  • detector, crop_size (default 1024), feather_px (24) - the mechanics above.
  • composite_method (laplacian default) plus color_match, grain_match, sharpness_match - the integration stack that makes the result blend. match_directional_lighting is same-character mode only; leave it off for cross-identity swaps or it imposes the original person's skull geometry on the new identity.
  • dry_run skips the API call and shows you the prompt that would be sent - free debugging. ref_cap_px (1024) downscales refs, which saves bandwidth and actually improves identity transfer; 4K skin-pore detail confuses the model.

Outputs

The four outputs are (IMAGE, STRING, MASK, IMAGE): image (the result, or a red-tinted placeholder on refusal), status (OK / REFUSED:<category> / ERROR:<reason>), mask (the feathered alpha composite in full-image coordinates - handy if you want to inspect or reuse it), and debug_sheet - a 2x2 montage of tight bbox, expanded bbox, the square sent, and the square returned. That last one is your friend when something looks off; it tells you instantly whether the model or the compositing is to blame.

Install

Same as the rest of the pack - it's in ComfyUI Manager if you search "NanoBanana FaceSwap," or manually:

cd ComfyUI/custom_nodes
git clone https://github.com/IxMxAMAR/ComfyUI-NanoBanana-FaceSwap
cd ComfyUI-NanoBanana-FaceSwap
pip install -r requirements.txt

Restart ComfyUI. Heavy dependency alert: this is an API node, not a local model, so there's no big checkpoint to download - but mediapipe is required for the auto cascade, so run the requirements even if you only want one node. You'll need a Gemini API key either in the env or pasted into api_key.

Troubleshooting

  • REFUSED:<category> - red output means the classifier fired. That's the node working as designed; try auto_relax_on_refused or fall back to the pack's mask-inpaint or obfuscation pathways.
  • Face landing misaligned - almost always the crop math, but only if you've been in the source. In practice, re-check scope: face keeps hair, so if you wanted a full head replacement and only swapped the face, it'll look wrong.
  • ERROR:detector_unavailable:mediapipe - you skipped the requirements install.

Batch tip: batch_axis lets you iterate frames (target) or identities against a fixed target, and each iteration is its own API call with its own retry - one refusal doesn't kill the batch.

CategoryNanoBanana FaceSwap

Inputs (32)

NameTypeDefaultDescription
api_keySTRING
modelCOMBOgemini-3.1-flash-image-preview3 options: gemini-3.1-flash-image-preview, gemini-3-pro-image-preview, gemini-2.5-flash-image
target_imageIMAGE
identity_1IMAGE
scopeCOMBOhead3 options: face, head, head+styling
grid_modeCOMBOseparate_refs2 options: separate_refs, auto_sheet
custom_hintSTRING
safety_thresholdCOMBOBLOCK_NONE4 options: BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE
seedINT00–2147483647
batch_axisCOMBOtarget2 options: target, identity
detectorCOMBOauto4 options: auto, mediapipe, opencv_yunet, gemini_bbox
crop_sizeINT1024256–2048
histogram_matchBOOLEANfalseLegacy RGB histogram match. Superseded by color_match below; keep off unless debugging.
feather_pxINT240–256
image_sizeCOMBO2K3 options: 1K, 2K, 4K
color_matchBOOLEANtrueLAB color match with face-polygon stats. Fixes skin-tone cast.
grain_matchBOOLEANtrueAdd synthetic Gaussian noise matching the target's cheek variance.
sharpness_matchBOOLEANtrueBlur Gemini's face if it's sharper than the body. Never sharpens.
composite_methodCOMBOlaplacian2 options: laplacian, feather
match_directional_lightingBOOLEANfalseSame-character mode. Imposes the original face's lighting envelope on the new face. Corrupts identity for cross-identity swaps.
lab_strengthFLOAT0.600–1
grain_strengthFLOAT1.000–2
identity_2optIMAGE
identity_3optIMAGE
identity_4optIMAGE
identity_5optIMAGE
identity_6optIMAGE
dry_runoptBOOLEANfalseSkip API call; return a structured preview of the prompt + parts.
timeout_msoptINT1800005000–600000
ref_cap_pxoptINT10240–4096Downscale ref longest-edge to this px. 0=off.
auto_relax_on_refusedoptBOOLEANfalseOn refusal, retry once with no safety_settings.
networkoptNB_NETWORKOptional. Wire a NanoBanana - Network Route node here to route this swap's API call through that proxy (e.g. US egress).

Outputs (4)

NameTypeDescription
imageIMAGE
statusSTRING
maskMASK
debug_sheetIMAGE