Save Video Websocket
Send the finished video down the websocket instead of hunting for a file on disk
- video
The name is honest: this node takes a finished video and streams it to your web client over ComfyUI's websocket instead of writing it to disk. If you're building an app, a custom UI, or any client that wraps the ComfyUI backend, that's exactly the hole it plugs.
Why you'd reach for it. ComfyUI already does this for images - SaveImageWebsocket is how the default frontend shows you previews. There was no video equivalent for a long time, so people building web clients either polled the output folder, glued in a VHS path, or hand-rolled a binary websocket handler (ask anyone who's done it: the "get the image back over the socket" step is where a full day disappears). This node is the video-shaped version of that trick. Wire it where you'd normally put SaveVideo and the MP4 lands in your client's onmessage instead of on disk. The pack is by Jonnathan Nakagawa (nakagawa.dev), it's MIT, and it's a genuine niche utility - don't expect a big community footprint, there isn't one yet, but for this one job it's the smallest thing that works.
How it works. It takes ComfyUI's native VIDEO type - the same object SaveVideo takes - and calls its save_to() into a temp file, which hands the encode off to PyAV. Then it reads the bytes back and frames them: a VIDF magic, a 4-byte little-endian format length, the format string (mp4), then the raw video. That payload goes through PromptServer.send_sync with event type 100, and ComfyUI's server slaps its own 4-byte event-type header on the front before pushing a binary frame down the socket. On the client you skip those first 4 bytes, check for VIDF, read the format, and the rest is your video:
ws.onmessage = (e) => {
if (e.data instanceof ArrayBuffer) {
const view = new DataView(e.data);
if (view.getUint32(4) === 0x56494446) { // "VIDF"
const fmtLen = view.getUint32(8, true);
const format = new TextDecoder().decode(new Uint8Array(e.data, 12, fmtLen));
const video = e.data.slice(12 + fmtLen);
document.querySelector('video').src = URL.createObjectURL(new Blob([video], {type: `video/${format}`}));
}
}
};
Note the constant up there is 0x56494446, not the 0x46444956 the README prints - the README's value only matches a little-endian read, so its snippet silently never fires. You've been warned. The README also calls that first header a "message length"; it's actually the event type. Doesn't matter, you skip it either way.
The inputs. All three are required, and all three have sane defaults:
video(VIDEO) - the video object from whatever native video node is upstream of you.format(auto / mp4) - the container. The dropdown is populated by your ComfyUI build, not the pack; on current core it's just these two, so the README's "webm, avi, mov" list is aspirational.codec(auto / h264) - same deal, an enum your build defines.
Here's the useful bit: format=auto plus codec=auto makes save_to remux the stream as-is - no re-encode, fastest path, zero quality loss. Only pick explicit values when you actually want a conversion.
It's an output node, so there are no outputs to wire. It sits in api/video and does one thing, terminally.
Install. ComfyUI Manager can find it (search "nakagawa"), or the manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/nakagawadev/comfyui_nakagawa
# restart ComfyUI
No models to download. One real gotcha, though: the pyproject.toml declares zero dependencies, but the module imports PyAV (av) and comfy_api.util at load time. That second one is the native video API that only exists in newer ComfyUI builds. On a current install both are already there, but on an older ComfyUI the entire module fails to load and the nodes just don't appear - no error dialog, they're simply missing. If that happens, update ComfyUI before you debug anything else.
Like every custom node, you're running someone's code with your user account, and the custom-node ecosystem has a documented security problem, so eyeballing a ~200-line file before you trust it is cheap insurance. This one makes no network calls - it only pushes bytes down your local websocket.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| video | VIDEO | The video to send through websocket | |
| format | COMBO | auto | The format to save the video as |
| codec | COMBO | auto | The codec to use for the video |
Outputs (0)
No outputs