ntl Send Images (WebSocket)
Beam Images Out of ComfyUI Over WebSocket — Past the 4MB Wall
- images
This node is the other half of the same pack, and it exists to solve one specific problem: getting your generated images out of ComfyUI and into code you wrote. Give it an IMAGE tensor and it pushes the image over ComfyUI's websocket as base64, chopped into chunks - and the chunking is the entire point.
Its ancestor, Acly's External Tooling Nodes, could send images the same way but hit a wall: one websocket message can only carry so much, and a base64 blob of a big PNG slams into it around the 4MB mark. This rewrite splits the base64 into partlen-sized pieces and lets your client reassemble them, which is why the README brags in its first bullet: "can send batch imgs much more than 4MB." If you're building your own front-end - a Krita-style plugin, a web UI, a headless script - this is how you get finished images back without ever touching the output folder.
How it works
For every image in the batch it does the same thing: tensor to numpy, save as PNG, base64-encode the bytes, then slice the string into partlen-chunks. Each chunk goes out over the same websocket the ComfyUI frontend uses, as a ntlb64part message carrying {nodelabel, img_idx, part_idx, part_b64}. Your client's job is to listen for those messages, stash chunks by node → image → part, verify the parts arrived in order (the README's _is_continuous helper does exactly this), then join and decode back into a PIL image. The ordering check matters because websocket messages from multiple nodes can interleave.
The inputs you'll actually set
Three inputs, two of them worth touching:
- images: the IMAGE tensor(s) you want sent. Wire it off a VAE decode, an upscaler, anywhere you've got a finished image.
- nodelabel (STRING): your own tag, say
"main"or"upscaled". This is how your client tells one node's stream apart from another - it must filter on the exact same string or you'll silently get nothing. - partlen (INT, default 1048576): chunk size in characters. That default - 1 MiB of base64 per message - is the sane setting. It's the knob that beats the 4MB wall, so don't crank it to 50MB to cut message count; you'd just rebuild the bug the node exists to avoid.
There are no outputs - it's an output node, nothing wires out of it.
Where people get burned
- Nothing happens? Most likely nobody is subscribed. The node writes no file and the stock ComfyUI frontend won't render these images - it only works if your code is listening for
ntlb64part. Wire it up, run it, and check your client before suspecting the node. - nodelabel mismatch is the silent killer: client listening on one label while the node emits another, and every message vanishes.
- It always re-runs.
IS_CHANGEDreturns a random value, which is deliberate for an output node - you can't cache-trick it, and it means the images go out on every queue execution whether the inputs changed or not.
Install
Same pack as its sibling, LyazS/comfyui-nettools ("net tool node for comfyui"). In ComfyUI Manager, search "net tool node for comfyui", or:
cd ComfyUI/custom_nodes
git clone https://github.com/LyazS/comfyui-nettools
Restart ComfyUI after. No requirements.txt, no models, no keys - the node runs on Python stdlib plus the PIL/numpy/torch that ComfyUI already bundles, all in one readable __init__.py. If you're wiring an external client into ComfyUI and the default preview isn't enough, this is the small, self-contained piece you were missing.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| nodelabel | STRING | — | |
| partlen | INT | 1048576 | — |
Outputs (0)
No outputs