Kavel Edit Image
Describe the change, skip the mask — the smarter half of ComfyUI-Kavel
- image
- image
- url
Kavel Edit Image is the more interesting node in this pack. Feed it any IMAGE from your graph plus one sentence - "put the product on a white marble surface; keep the label unchanged" - and you get back a re-rendered image and a CDN url. No mask to paint, no denoise strength to guess, no inpainting model to babysit.
That's a genuinely different capability from local inpainting. A mask asks you where and how much; an instruction model reads your sentence and decides what changes. For product shots, background swaps and "fix the thing I already generated", it's often one node instead of a chain. The local contender is Qwen-Image-Edit, and it's good, but it has its own drift problems - the troubleshooting doc has a whole entry on the face sliding across successive edits.
How the round trip works
The mechanism is short and one step of it matters for privacy. Your tensor becomes a PNG in memory (clipped to 0–1, saved as PNG bytes), then goes up as multipart form data to Kavel's storage endpoint at /api/storage/upload-image. That returned URL is what the model actually reads. Then the node submits an image-to-image task, polls every 5 seconds for up to 360 seconds, downloads the result and converts it back to a float32 IMAGE.
So yes: your input image is uploaded to a third-party CDN every time the node executes. That's how it works, not a misconfiguration. The free tier runs nano-banana-2-lite; with a key you name the model, and the author's suggestion here is nano-banana-2 for multi-reference edits. When a response includes a watermark-free variant, the client prefers it, so a paid plan means a clean result.
Inputs and outputs
image is required and typed IMAGE, which is the good part - this is any image in your graph. A local SDXL render, an upscale, a photo from Load Image; the node doesn't care.
instruction is a multiline string, pre-filled with that marble-product example. Treat it as the entire prompt, because it is one. The README's advice is right: say what must not change as clearly as what should, since the model invents whatever it can't see - "keep the label unchanged" is doing real work in the default. There's no mask, no strength, no negative, no resolution field. One text box is the whole interface, so if you wanted a slider, this isn't the node.
api_key and model behave as on the generate node, trap included: model is only read when a key is present, so an empty key quietly sends you to the free model no matter what you typed.
seed is never sent to Kavel - it exists only to defeat ComfyUI's cache so an unchanged instruction re-runs. Change the wording, or change the seed; the seed won't change the picture for any other reason.
Outputs are image (IMAGE) and url (STRING). The image goes wherever an image goes: Save Image, an upscaler, or back through this node for a second pass. The url is the permanent CDN link. is_output_node is false, so wire it to something or Queue does nothing.
One gotcha that isn't in the README: the tensor-to-PNG helper uses image[0], so a batch only sends its first frame. Pass single images, or split the batch first.
Install
ComfyUI Manager, search Kavel, install, restart. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/hanshs474/ComfyUI-Kavel
That's all of it. No Python dependencies (the client is standard-library urllib, and pyproject.toml declares an empty dependency list), no model files, no weights. To run on your account, export KAVEL_API_KEY before starting ComfyUI.
When it goes wrong
The quota wall. The free tier gives a few images a day per machine, and running out shows up as an error telling you to paste a key - except it arrives disguised as an HTTP 200 with a success code, with only an extra flag marking it. Don't retry; the day's free pool is gone.
"Kavel refused this prompt." The task comes back failed and the client raises that instead of resubmitting. That's the model-side filter, not the node - the Nano Banana line is tightly moderated - so reword the instruction rather than pressing Queue again.
"upload failed." That's the CDN step, so it usually means network: a proxy, VPN or firewall blocking kavel.ai kills this node before the model sees your image. And if you edited nothing and got the same picture back, check whether the node ran at all - ComfyUI skips it when inputs are identical. Bump the seed, or set control_after_generate to randomize; node plumbing explains why this bites everybody once.
The honest framing: brand-new, vendor-published pack - one commit, links tagged for the vendor's analytics, and no Reddit discussion I could find. The code is short and clean and does what the README says, but you are pasting photos of your work onto someone else's CDN. Fine for mockups. Think twice before routing client deliverables through it.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| instruction | STRING | put the product on a white marble surface; keep the label unchanged | — |
| api_keyopt | STRING | Optional. Leave empty to use the free tier (no account, watermarked, a few images a day). Paste a key from kavel.ai/settings/apikeys to run on your account with any image model your plan includes. KAVEL_API_KEY in the environment works too. | |
| modelopt | STRING | Only used with an API key, e.g. nano-banana-2 | |
| seedopt | INT | 00–4294967295 | Change to force a new run |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| url | STRING | — |