Webcam Capture
Webcam Capture for ComfyUI
- captured_image
Webcam Capture is the node that turns your camera into a normal IMAGE tensor, the kind every img2img, inpainting, and ControlNet workflow already eats. Instead of dragging a screenshot or a phone photo in, you press Start Capture on the node, look at the lens, and the next queue run feeds the current frame straight into the graph. It's the classic "put your own face through a Turbo/LCM model and watch yourself get stylized" setup, or a crude motion-capture input if you're feeding it into a pose ControlNet. It won't win awards for polish, but it's the least-friction way to get from camera to sampling that I've found.
The name is also a small lie in your favor: nothing here calls an API and no key is involved. Everything stays on your machine.
How it actually works
The mechanism is split across three pieces, and it's worth knowing because it explains every quirk. The node's real work happens in your browser, not in Python:
- The frontend extension (
js/node.js) draws a camera picker, a Start Capture button, a live preview thumbnail, and a Stop Capture button onto the node. Clicking Start asks the browser for camera access vianavigator.mediaDevices.getUserMedia, grabs a frame every second, and previews it right in the node. - Each grabbed frame is POSTed as a PNG blob to a custom server route,
/webcam_capture(server_extension.py), which saves it tocaptured_image.png. - When you run the queue, the Python node (
webcam_capture_node.py) opens that file, converts it to a float tensor, and hands it to the rest of the graph.
So it's stills, not a live stream: every execution reads the latest saved frame off disk. It's a webcam, but with a server round-trip and a 1-second tick in between.
The inputs and outputs that matter
There's exactly one input, and it does almost nothing:
- seed (INT) - this is the "seed trick" the README mentions. The value itself is never used for anything. It exists so the node has a required widget you can bump, which forces ComfyUI to re-run it on the next queue. In auto-queue mode, changing the seed between runs keeps fresh frames flowing instead of letting the node sit cached. If the node isn't re-executing, change this and it will.
The one output:
- captured_image (IMAGE) - wire this into any node that takes an image input: Load Image-style slots, VAE Encode for img2img, ControlNet, IPAdapter, you name it. It's a bog-standard batch-of-one image tensor, so it plugs into everything.
Installing it
Install it from ComfyUI Manager (search comfyui-webcam-node), or the manual way:
cd ComfyUI/custom_nodes
git clone https://github.com/uetuluk/comfyui-webcam-node
Then restart ComfyUI. The pack ships with zero extra Python dependencies - it leans on Pillow, numpy, and torch, which ComfyUI already has - and there are no model files to download. Find it under Webcam → Webcam Capture.
Where people get burned
- It must run on localhost or HTTPS. Browsers refuse
getUserMediaon a plain-HTTP LAN address, so if you access ComfyUI overhttp://192.168.x.x:8188, the camera buttons just won't work. The README calls this out directly - use127.0.0.1:8188or set up a reverse proxy with TLS. - Press Start Capture before you queue. The node reads
captured_image.pngfrom disk at execution time. If you never started the camera, that file doesn't exist and the node errors out. Get in the habit of Start → look at the preview → queue. - The file is shared and clobberable. Every node and every open tab saves to the same
captured_image.pngin ComfyUI's working directory. Two webcam nodes in one graph will stomp on each other, and the path is relative to wherever you launched ComfyUI, so watch out if you run it from odd directories. - Switching cameras mid-capture isn't supported - the frontend explicitly refuses to swap devices while recording. Pick your camera, then start.
Honestly, for a one-off "is this actually me?" img2img experiment it's great. For production video you'd want something like a real streaming or NDI-based input - but you don't want that for your first try anyway.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| seed | INT | 00–18446744073709550000 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| captured_image | IMAGE | — |