Nodes/ComfyUI VideoMark/VideoMark Video
ComfyUI Node

VideoMark Video

Watermark and end cards in one node, if your ComfyUI is new enough

By kaerozhi·Created 24 days ago·Updated 14 days ago· 4
VideoMark Video
  • video
  • logo
  • logo_mask
  • video
◄modecorner►
◄positionbottom_right►
◄text© 2026 kaero►
◄opacity0.85►
◄scale20.0►
◄margin32►
◄use_texttrue►
◄use_logofalse►
◄layoutvertical►
◄color#FFFFFF►
◄stylesoft►
◄use_stroketrue►
◄stroke_width3►
◄stroke_color#000000►
◄stroke_opacity0.55►
◄use_shadowtrue►
◄shadow_color#000000►
◄shadow_opacity0.40►
◄shadow_offset5►
◄shadow_blur8►
◄angle0.0►
◄font(built-in fallback font - CJK glyphs render as boxes)►
◄font_file►
◄float_pathdiagonal►
◄float_cycles1.0►
◄seed0►
◄start_pct0.000►
◄end_pct1.000►
◄fade_frames0►
◄tile_gap90►
◄title_modeoff►
◄title_seconds2.0►
◄title_text►
◄title_bg_color#000000►
◄logo_file►
◄text_in—►

VIDEO in, VIDEO out, everything done

VideoMark Video is the pack's convenience node: feed it a ComfyUI VIDEO, and it paints the watermark onto the frames, optionally glues a copyright card on the head and/or tail, keeps audio in sync, and hands you a VIDEO back. One node instead of three - no decode-to-IMAGE step, no re-encode step, and no frame rate to declare by hand, because it reads that off the video.

This is the node for the 2026 workflow shape where the model already emits a VIDEO. LTX-2 and MiniMax H3 land there, and Wan pipelines reach it through Create Video. If your graph currently ends … → Save Video, dropping this in the middle is a two-wire change.

The tradeoff of a convenience node is that it hides its seams, and this one has three: the card's text size follows the watermark's scale rather than having its own, the card never gets a stroke, and there's no separate head/tail text. If you want to style the card and the watermark independently, you want Overlay + Title chained instead. If you want "watermark plus a copyright card, don't make me think", this is the one.

No community signal to lean on either - a corpus search for "videomark" across two years of r/StableDiffusion, r/comfyui and r/civitai comes back empty, and most actual watermark discussion there is about removing marks, not adding them.

How it works

It pulls the video apart with get_components(): an IMAGE tensor plus frame_rate, audio, metadata and alpha. The watermark renderer is the same code the Overlay uses - one RGBA stamp sized to the frames, alpha-composited per frame, stroke and shadow baked in - and the card, if enabled, is title_seconds × fps frames of solid colour with text and logo laid out the same way, concatenated at the ends.

Then it rebuilds a VIDEO, preserving the input's bit depth and colour space and writing the frame rate back. One honest detail: if cards changed the frame count, the original alpha channel no longer matches the picture, so it's dropped rather than encoded wrong. Source with real transparency loses it. Everything is numpy + Pillow - no dependencies, no VRAM, no model.

The inputs you'll actually touch

  • video - the only required input; everything else has a default.
  • mode (corner, center, floating, tile) with position, then text, opacity, scale, margin. Same rules as the Overlay: scale is a percentage of frame width so it survives a resolution change, margin is in pixels, and center/tile want opacity down around 0.12–0.22.
  • title_mode - off (default), head, tail, both - with title_seconds (2 is standard) and title_text. Leave title_text empty and it inherits text, which means one text_in wire feeds both the watermark and the card.
  • title_bg_color for the card, plus style and the stroke/shadow controls for the watermark, and the optional logo / logo_mask / logo_file trio - use_logo is off by default, and a wired logo beats the uploaded file.

text_in behaves like the rest of the pack: connected and non-empty wins, blank falls back to the typed text. Output is a single video, straight into Save Video.

Install

# ComfyUI Manager: search "comfyui-videomark"
cd ComfyUI/custom_nodes
git clone https://github.com/kaerozhi/comfyui-videomark.git

Also available as comfy node install comfyui-videomark. No pip step: the pack declares zero dependencies and rides on the torch/numpy/Pillow ComfyUI already ships. Restart afterwards.

Where people get burned

The node isn't there at all. It only registers if your ComfyUI exposes the comfy_api.latest VIDEO types. The pack imports them at load time and skips the node entirely if they're missing, printing a [VideoMark] line about the failed VIDEO import to the console. On an older install you get Overlay and Title and no sign of the third node. Updating ComfyUI is the fix - it isn't a pack bug, and it's the one gotcha unique to this node.

A card bigger than you expected. Card text and logo sizes follow scale, the watermark's own percentage. Bump scale for a bigger card and you've made the watermark bigger too. Chained Overlay + Title avoids that, since Title has its own logo_scale and text_scale.

A watermark that isn't there. If rendering throws, the node logs one [VideoMark] line and passes the video through untouched. You get a clean clip, not an error - read the console before debugging your wiring.

Missing font glyphs. 黑体 (simhei) has no ©, so a copyright line renders as a box there. Use 微软雅黑 / 宋体 / 楷体, or point font_file at a font file.

Dark shadow on dark footage. Invisible by definition. Keep the stroke, or set shadow_color light - same advice as the rest of the pack.

Editing the panel without a restart. The panel under web/ is scanned at startup, so changing an existing JS file only needs Ctrl+Shift+R, while adding a new one needs a ComfyUI restart.

CategoryVideoMark

Inputs (39)

NameTypeDefaultDescription
videoVIDEO—
modeCOMBOcornerWatermark mode: corner fixed in one corner (least intrusive, best default) center dead centre - keep opacity around 0.15~0.25 floating wanders inside the safe area (hardest to crop out, worst to watch) tile repeated across the whole frame - hardest to remove in post
positionCOMBObottom_rightWhich corner to use in corner mode. Bottom-right blocks the least; switch to top-left if the platform overlays its own UI (like/share buttons) there.
textSTRING© 2026 kaeroWatermark text. Multiple lines supported - just press Enter.
opacityFLOAT0.850.02–1Overall opacity. Reference values: corner 0.75~1.0 (needs to stay legible) centre / tile 0.12~0.22 (higher starts to hurt viewing) floating 0.25~0.45 (too low gets erased after compression)
scaleFLOAT20.01–100Watermark width as a percentage of the frame width. Resolution independent - you never retune it. 15~25 for text, 8~18 for a logo.
marginINT320–600Safe margin from the frame edge, in pixels. Floating and tiled stamps respect it too, so nothing ever gets clipped. 24~40 for 736x992; 36~64 for 1080p.
use_textBOOLEANtrueTurn off to show the logo only without deleting the text.
use_logoBOOLEANfalseMaster switch for drawing the logo. Source is either the panel upload (stored as logo_file above) or an IMAGE linked to the logo input - the link wins.
layoutCOMBOverticalHow logo and text stack when both are present: vertical (logo on top) or horizontal (logo on the left).
colorSTRING#FFFFFFText colour. Accepts #RRGGBB / #RGB / r,g,b / a colour name.
styleCOMBOsoftStyle preset - one click swaps the whole stroke / shadow set: soft both on but subtle (default) readable on light and dark footage, without grabbing attention plain both off - cleanest, but may vanish on bright backgrounds outline solid stroke only - only needed when contrast swings hard outline_shadow both maxed - most legible, also most noticeable manual ignore presets, use the four controls below Note: presets override the stroke / shadow values below - pick manual to tune them yourself.
use_strokeBOOLEANtrueStroke switch (only read when style=manual; presets take over otherwise). A stroke rings the glyphs and reads louder than the text itself on high-contrast shots - if the watermark feels heavy, lower stroke_opacity before turning it off.
stroke_widthINT30–24Stroke thickness in pixels. Only applies when the stroke is on. 2~4 is plenty.
stroke_colorSTRING#000000Stroke colour.
stroke_opacityFLOAT0.550–1Opacity of the stroke itself - lower this first when the watermark feels heavy; keeps more legibility than switching it off. 1.0 = solid black outline (loudest); 0.5~0.6 = soft ring (default); 0 = same as off.
use_shadowBOOLEANtrueShadow switch (only read when style=manual). A shadow thickens the silhouette without the hard edge a stroke leaves - ⚠ a dark shadow is invisible on night / black footage - use a stroke there, or lighten shadow_color.
shadow_colorSTRING#000000Shadow colour. Dark shadows disappear on dark footage; use a light colour like #FFFFFF.
shadow_opacityFLOAT0.400–1Opacity of the shadow. 0.3~0.5 reads as 'visible outline, not in the way'.
shadow_offsetINT5-80–80Shadow offset in pixels (positive = down-right). 4~8 looks natural; 0 turns it into a symmetrical soft glow - lighter, and costs no margin in a corner.
shadow_blurINT80–100Shadow blur radius in pixels. Bigger is softer. 6~14 is natural; 0 = a hard duplicate.
angleFLOAT0.0-180–180Rotate the whole watermark. For tiled marks, -20~-30 degrees is much harder to align and erase.
fontCOMBO(built-in fallback font - CJK glyphs render as boxes)Font. Sorted CJK-first on Windows (Microsoft YaHei / SimHei / SimSun / KaiTi ...). Fonts you drop into ComfyUI's input/fonts folder show up in this list too. Note: SimHei has no glyph for © - it renders as a box. Use Microsoft YaHei / SimSun / KaiTi for text containing ©.
font_fileSTRINGFont file path relative to ComfyUI's input folder, e.g. fonts/MyFont.otf. When set and the file exists it overrides the font list above. Absolute paths and '..' are rejected.
float_pathCOMBOdiagonalPath followed while floating: diagonal / horizontal / vertical constant back-and-forth (triangle wave) circle elliptical loop random uniform random jumps - strongest anti-theft, most jarring
float_cyclesFLOAT1.00.1–200How many round trips across the whole clip. 1 = one very slow pass; 4~8 = clearly wandering but still readable. For the random path this means 'number of position changes' - try 2x the clip length in seconds. A single still has nothing to travel across: the seed pins it to one spot.
seedINT00–4294967295Used by the random float path only. Fix it to reproduce the same positions.
start_pctFLOAT0.0000–1Where the watermark starts appearing, as a fraction of total length. 0 = from frame one. Only meaningful for multi-frame sequences: a single still counts as frame 0.
end_pctFLOAT1.0000–1Where it stops, as a fraction of total length. 1 = stays to the end. e.g. 0.6 -> 1.0 shows it only in the last 40%. Only meaningful for multi-frame sequences: a single still counts as frame 0.
fade_framesINT00–240Fade-in / fade-out length in frames. 0 = hard cut. Only meaningful for multi-frame sequences: a single still has nothing to fade.
tile_gapINT900–1200Spacing between tiled watermarks, in pixels.
title_modeCOMBOoffHead / tail black copyright card. off = do not add one.
title_secondsFLOAT2.00.1–60Card duration in seconds. Frame rate comes from the input video.
title_textSTRINGCard text. Leave blank to reuse the watermark text above.
title_bg_colorSTRING#000000Card background colour.
logo_fileSTRINGLogo file name, relative to ComfyUI's input folder. Clicking 'Upload logo' in the visual panel fills this in; you normally never edit it by hand. You can also type the name of a file already placed in the input folder, e.g. logo/kaero.png. Note: a linked IMAGE on the logo input always wins over this.
text_inoptSTRINGOptional. Feed the text in from another node (any node that builds a string). When connected and non-empty the wired text wins - whatever you typed in the panel is ignored. Disconnected, or an empty string upstream, falls back to the panel text. Typical use: while comparing parameter variants (resolutions / LoRA strengths / seeds), splice this run's parameters into the frame so you can tell at a glance which settings produced it. Note: it takes one plain string - nothing is filled in for you, so build the text you want upstream.
logooptIMAGEOptional. A PNG logo with an alpha channel. Only drawn when use_logo is on. Transparency comes from logo_mask first; falls back to the PNG's own alpha.
logo_maskoptMASKOptional. Transparency mask for the logo; falls back to the PNG's own alpha. ComfyUI's Load Image outputs a PNG's transparency as a MASK - just wire it in.

Outputs (1)

NameTypeDescription
videoVIDEO—