Roop Webhook: Image Tensor
Ship a generated image to any webhook — no API keys required
- image_tensor
You swapped a face, or generated an image, and now you need it somewhere else: a Discord bot, your own server, an automation endpoint, a pipeline that only accepts files. This node takes an image tensor, saves it, and POSTs it to a webhook URL as a multipart file upload. The name is a lie in the best way - it doesn't call any branded API and needs no key. A URL and (optionally) a shared secret are the whole setup.
This is the node people skip past when they're staring at the face-swap nodes, which is a shame, because it's the part of the pack that actually makes it a pipeline rather than a one-off. The pack is built around running roop on a remote box - a Colab T4, a cloud VM - and the webhook nodes are how results get off that box and into something persistent.
How it works
Mechanically it's simple: the node saves the incoming image_tensor to roop_dir/temp_io/<filename>, reads it back as bytes, and fires a requests.post with the file as multipart form data:
POST <webhook_url>
Content-Type: multipart/form-data
file: <filename> (image/png)
If you set webhook_secret, it also sends a GitHub-style signature header - X-Hub-Signature-256: sha256=<hex> - computed as an HMAC-SHA256 of the file bytes using your secret as the key. Your endpoint can verify that header to be sure the request really came from your ComfyUI, which matters when the webhook is a public URL.
The inputs that matter
- image_tensor - any IMAGE output from your graph. The swapped result, a preview, whatever.
- webhook_url - where to send it. Leave empty and the node does nothing (see below).
- webhook_secret - shared secret for the HMAC header. Optional, but if your endpoint is reachable by strangers, use it.
- filename - what the receiver sees as the uploaded filename. Default
output.png. - enable_webhook - master switch, default on.
- roop_dir - used only as a scratch location to write the temp file. Default
/content/roop.
There are no outputs. It's a fire-and-forget node; the only record is the console line [WebhookImage] Sent image: <filename> → <url> or an error.
Where people get burned
- Silent skips. If
enable_webhookis off orwebhook_urlis empty, it just printsDisabled or URL not set - skipping.and moves on. If nothing's arriving, check both. - Your endpoint has to accept multipart file uploads. A plain GET-only URL won't do. Most webhook platforms (Discord, Zapier-style tools, custom Flask/FastAPI handlers) expect exactly this shape, but if you're hitting a bespoke API, confirm it parses the
filefield. - No retries, no queue. One POST, and if it fails (bad URL, timeout, 4xx) the error goes to the console and the image is gone. Don't use this for anything you can't afford to re-run.
- It inherits the pack's habits - the bare temp path defaults to
/content/roop, so setroop_dirto something writable on your machine.
Installing it
Same pack as the rest of the Roop nodes: clone it into custom_nodes and restart.
cd ComfyUI/custom_nodes
git clone https://github.com/glitchinthemetrix16/ComfyUI-Roop
The README lists requests as a dependency, which ComfyUI already ships. Unlike the swap nodes, this one doesn't need a roop checkout to work - the roop_dir field just needs to point at a writable folder for the temp file. You can actually use this webhook node in any graph, with or without a face swap attached.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| image_tensor | IMAGE | — | |
| filename | STRING | output.png | — |
| webhook_url | STRING | — | |
| webhook_secret | STRING | — | |
| enable_webhook | BOOLEAN | true | — |
| roop_dir | STRING | /content/roop | — |
Outputs (0)
No outputs