Nano Banana - Unbiased Face Swap
A hardened request shape that sometimes gets through
- target_image
- identity_1
- identity_2
- identity_3
- identity_4
- identity_5
- identity_6
- network
- image
- status
- mask
- debug_sheet
Every swap node in this pack fights Gemini's safety classifier a different way. NanoBananaUnbiasedFaceSwap is the one built specifically for celebrity and public-figure references - the pack calls it "unbiased" because it changes the shape of the request rather than the pixels. It's the most fragile path in the pack, and the most likely to need a VPN. Read that before you get excited.
What makes it different
The other pathways send a conventional request and let you tune safety_threshold. This one uses a hardened request shape that empirically gets past Gemini's celebrity classifier, and it's all in how the call is constructed:
- A
system_instructiongiving the model a "biometric compositing engine" persona - A JSON-structured user prompt
response_modalities=["IMAGE"]only - no TEXT escape hatch for the model to refuse through- No explicit
safety_settings- it uses Gemini's own defaults rather than asking for BLOCK_NONE - A flat parts list, no
Content(role=)wrapper, no text labels between image parts
That last batch of details matters more than it looks like it should. The author's workflow notes say this request shape is the difference between a refusal and a pass - and also that it's fragile: Google can tighten the classifier server-side any week and quietly break it.
The geography problem
Here's the part that surprises people: it may simply not work from EU IPs. The pack's own pre-flight instruction is to connect a VPN exit in a permissive region (US works) before queuing, because EU IPs - Germany especially - reliably block celebrity refs regardless of request shape. This isn't paranoia baked into a README; it matches the January 2026 policy tightening where Google strengthened IMAGE_SAFETY and celebrity restrictions. If you're in Europe and this node refuses everything, the first thing to try is changing egress, not changing settings.
Inputs that matter
api_key,model,target_image,identity_1..identity_6,scope,custom_hint,seed,batch_axis- the standard swap-node set.thinking_level(NONE default) - Pro's reasoning mode, if you want the model to reason about the edit.apply_integrate(default false) - this is the pack's staging switch. It gates the post-process integration stages (LAB color match, grain match, sharpness match, optional lighting transfer). Default off so your first test isolates whether the request shape alone gets through. Flip it on once the call succeeds.detector,mask_dilate_px(25),mask_feather_px(16),image_size,lab_strength,grain_strength,composite_method(feather default, laplacian optional), andmatch_directional_lighting- same-character only; it steals the original face's lighting envelope and corrupts identity in cross-identity swaps.- The usual v0.2 extras:
dry_run,timeout_ms,ref_cap_px,auto_relax_on_refused,network.
Outputs
The standard (IMAGE, STRING, MASK, IMAGE) - image, status, mask, debug_sheet.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/IxMxAMAR/ComfyUI-NanoBanana-FaceSwap
cd ComfyUI-NanoBanana-FaceSwap
pip install -r requirements.txt
Restart ComfyUI (or ComfyUI Manager → "NanoBanana FaceSwap"). Gemini API key required; httpx[socks] in requirements is there precisely so the node can route through a SOCKS proxy from the optional network input.
Troubleshooting
The ladder, in order: (1) connect the VPN, confirm egress is permissive; (2) run with apply_integrate=false to prove the call itself succeeds; (3) if a specific identity still refuses, chain the identity through IdentityRefObfuscator (blur + warp + LAB shift) to drop it under the recognition threshold; (4) if that fails, the whole pathway is a losing battle - Google tightened it server-side, come back in a few weeks. And honestly: this node is for legitimate, consented use. If the identity you're after is someone you have no business rendering, no request shape in the world changes that.
Inputs (28)
| Name | Type | Default | Description |
|---|---|---|---|
| api_key | STRING | — | |
| model | COMBO | gemini-3.1-flash-image-preview | 3 options: gemini-3.1-flash-image-preview, gemini-3-pro-image-preview, gemini-2.5-flash-image |
| target_image | IMAGE | — | |
| identity_1 | IMAGE | — | |
| scope | COMBO | face | 3 options: face, head, head+styling |
| custom_hint | STRING | — | |
| seed | INT | 00–2147483647 | — |
| batch_axis | COMBO | target | 2 options: target, identity |
| detector | COMBO | auto | 4 options: auto, mediapipe, opencv_yunet, gemini_bbox |
| mask_dilate_px | INT | 250–128 | — |
| mask_feather_px | INT | 160–128 | — |
| image_size | COMBO | 2K | 3 options: 1K, 2K, 4K |
| thinking_level | COMBO | NONE | 4 options: NONE, LOW, MEDIUM, HIGH |
| apply_integrate | BOOLEAN | false | Enable post-process integration stages (LAB color match, grain match, sharpness match, optional lighting transfer). Defaults OFF so the first call isolates the request-shape change. |
| lab_strength | FLOAT | 0.600–1 | — |
| grain_strength | FLOAT | 1.000–2 | — |
| composite_method | COMBO | feather | 2 options: feather, laplacian |
| match_directional_lighting | BOOLEAN | false | Same-character refinement only. Steals the original face's broad lighting envelope and applies it to Gemini's face. Imposes the original person's skull/brow geometry on the new identity in cross-identity swaps. |
| identity_2opt | IMAGE | — | |
| identity_3opt | IMAGE | — | |
| identity_4opt | IMAGE | — | |
| identity_5opt | IMAGE | — | |
| identity_6opt | IMAGE | — | |
| dry_runopt | BOOLEAN | false | — |
| timeout_msopt | INT | 1800005000–600000 | — |
| ref_cap_pxopt | INT | 10240–4096 | — |
| auto_relax_on_refusedopt | BOOLEAN | false | — |
| networkopt | NB_NETWORK | Optional. Wire a NanoBanana - Network Route node here to route this swap's API call through that proxy (e.g. US egress). |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| status | STRING | — |
| mask | MASK | — |
| debug_sheet | IMAGE | — |