Apply PuLID
Put a real face on an SDXL generation without training a thing
- model
- pulid
- eva_clip
- face_analysis
- image
- attn_mask
- MODEL
The whole point of the pack
Apply PuLID is the node you're actually here for. Everything else - the three loaders - exists to feed this one. You hand it a model, a reference photo of a person, and the three objects the loaders produced, and it returns a patched MODEL that will draw that person's face into your SDXL generation without you training a LoRA or describing anything. Wire the output into your KSampler and hit Queue.
This is cubiq's (Matteo's) native ComfyUI implementation of ByteDance's PuLID, and the "keep the prompt clean" angle is its whole identity. Earlier face adapters like InstantID or IP-Adapter FaceID work, but they leak - the identity injection degrades prompt adherence and image quality. The paper calls that ID pollution. PuLID's fix, contrastive alignment, trains two parallel branches, one identity-conditioned and one not, and a contrastive loss keeps the conditioned branch close to the unconditioned one's output distribution. Result: the face lands, and the rest of the image stays obedient. On SDXL it's the strongest zero-shot face adapter that doesn't punish your prompt.
How it actually works at queue time
When you press Queue, the Apply node does a whole pipeline before denoising starts. InsightFace detects the largest face, facexlib's FaceRestoreHelper crops and aligns it to 512px, a bisenet parser masks the background and turns it gray, the EVA-CLIP encodes the crop's appearance, and that's concatenated with the ArcFace identity embedding. The combined vector runs through an IDEncoder into per-layer linear projections that get added directly into SDXL's cross-attention at a specific set of transformer blocks. It's all weighted and scheduled, and it only runs at generation time - not when you drag the node on the canvas, which is why tweaking settings feels instant until you actually generate.
The inputs that matter
Three of them do the real work; the rest have sensible defaults.
- method -
fidelity,style, orneutral. Fidelity hugs the reference identity harder; style loosens the leash and lets the checkpoint express itself. Neutral skips the normalization and needs the weight dropped, or the face will smear. - weight - default 1, range −1 to 5. Up for more resemblance, down for subtlety. Start at 1, move in 0.1s.
- start_at / end_at - the sampling range the injection applies over (0 to 1). Narrow it to the middle of denoising to affect structure without pinning down texture.
attn_mask is optional but genuinely useful: a mask limits where the identity applies, so you can keep the face fixed while the background does whatever it wants. The output is MODEL - that's what goes into your sampler.
Install and setup
cd ComfyUI/custom_nodes
git clone https://github.com/cubiq/PuLID_ComfyUI
Restart (or Manager → search "PuLID"). Then three downloads: the PuLID checkpoint to models/pulid/, InsightFace's antelopev2 to models/insightface/models/antelopev2/, and the EVA-CLIP, which pulls itself. If this is the first PuLID node you're setting up, expect the antelopev2/InsightFace dependency dance to eat an afternoon.
Where people get burned
Reference quality is the #1 failure mode. The README says it twice: use a clean, sharp photo. Feed it a blurry one and no weight survives the encoder. Beyond that - the author built this against a 4-step SDXL-Lightning UNet, and it's the best-behaved combination; the Lightning LoRA notably is not. Other checkpoints can show quality degradation, so experiment with CFG and try the sgm_uniform scheduler if your default looks off. And if you're pairing this with IP-Adapter (a very common "PuLID for structure, FaceID for finish" setup), update the IP-Adapter extension - the README calls it out, and it's a stale-version crash people hit for weeks.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| pulid | PULID | — | |
| eva_clip | EVA_CLIP | — | |
| face_analysis | FACEANALYSIS | — | |
| image | IMAGE | — | |
| method | COMBO | 3 options: fidelity, style, neutral | |
| weight | FLOAT | 1.00-1–5 | — |
| start_at | FLOAT | 0.0000–1 | — |
| end_at | FLOAT | 1.0000–1 | — |
| attn_maskopt | MASK | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| MODEL | MODEL | — |