PixelSeal Low-Impact Embed
Watermark a finished video without anyone noticing — PixelSeal's quality-first path
- images
- watermarked_images
- watermark_id
- message_bits
The plain VideoSeal Embed Watermark node is the workhorse - robust, fast, good enough for most use. PixelSeal Low-Impact Embed is the one you reach for when the video is finished and you care more about invisibility than raw robustness: the client's master render, a portfolio piece, something that's going to be scrutinized frame by frame. It swaps in Meta's PixelSeal model, embeds every frame at full resolution, and leans on perceptual masking so the watermark costs you as little visual quality as possible. That's the whole pitch - the strongest watermark you can barely see.
How it's different from the regular embed
The pack's README is explicit: this is the quality-first path. Where the standard embed defaults to scaling_w=0.2 and processes in chunks with temporal strides, PixelSeal runs at scaling_w=0.15 with JND attenuation applied at the original resolution (full_resolution_jnd, default on). JND - just-noticeable-difference - is a model of where the human eye simply can't see changes, so the embedder pushes signal into texture and motion it knows you won't register. The result is the best imperceptibility-vs-robustness trade-off Meta's models offer.
The other headline feature is error correction for canonical IDs. If your watermark_id is a proper 128-bit ID in the wm_v1_ form (22 unpadded Base64URL characters after the prefix - the node's default is one), the node encodes it with a Reed–Solomon RS(32,16) code: 16 ID bytes plus 16 parity bytes. That lets the Detect node recover the ID even when up to eight bytes are corrupted, with no increase in watermark strength. Any other ID just uses the plain UTF-8 text format with a CRC32 checksum when it fits.
PixelSeal is a 256-bit model, so the full 32-byte RS codeword fits exactly. That's the one structural constraint: give it a valid wm_v1_ ID and you get the error correction for free; give it arbitrary text and you get the simpler format.
Inputs worth touching
watermark_id- use a canonicalwm_v1_ID to unlock the Reed–Solomon protection. That's the whole point of this node.scaling_w- starts at 0.15. Crank it down if you're paranoid about perceptibility; push it up if your output is going to be aggressively recompressed.full_resolution_jnd- keeps attenuation working at native resolution. Leave it on unless you hit a quality issue.
Then the temporal knobs: temporal_pooling (default off) merges frames together so the watermark is more consistent across time - turn it on for very noisy or fast-moving footage, and temporal_pool_size/temporal_pool_depth control how much history gets pooled. chunk_size (default 8) is how many frames process per pass. device is auto.
Outputs are the same trio as the regular embed: watermarked_images, the echoed watermark_id, and message_bits (256 here). Wire the images into your save node and you're done.
Install and gotchas
Same pack, same install - ComfyUI Manager search ComfyUI-VideoSeal, or:
cd ComfyUI/custom_nodes
git clone https://github.com/aperire/ComfyUI-VideoSeal
# restart ComfyUI
No pip dependencies get installed by the pack; the pixelseal checkpoint downloads on first run into a ckpts/ folder in your ComfyUI root.
Three things trip people up. First, there's no model dropdown - this node is hardwired to PixelSeal, so if you embedded something with videoseal, detect it with the VideoSeal Detect Watermark node set to videoseal, not with PixelSeal's extractor. Second, the first run downloads the checkpoint, so don't panic when it sits there - it's fetching, not hung. Third, if you see ModuleNotFoundError on first embed, your env is missing one of the vendored upstream's imports (omegaconf, timm, PyWavelets, scikit-image); a quick pip install fixes it.
Bottom line: when "nobody should be able to tell it's watermarked" is the requirement, this is the node. When you need to survive heavy abuse instead, the plain VideoSeal embed is the more forgiving choice.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| watermark_id | STRING | wm_v1_N4q7Zt2Lx8cVp3Rm6Kj9Aw | — |
| device | COMBO | auto | 3 options: auto, cuda, cpu |
| scaling_w | FLOAT | 0.150.01–1 | — |
| chunk_size | INT | 81–128 | — |
| full_resolution_jnd | BOOLEAN | true | — |
| temporal_pooling | BOOLEAN | false | — |
| temporal_pool_size | INT | 42–16 | — |
| temporal_pool_depth | INT | 21–7 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| watermarked_images | IMAGE | — |
| watermark_id | STRING | — |
| message_bits | INT | — |