Send Http request
The webhook node that forgets to serialize its images
- images
This node does exactly one thing: take the image(s) ComfyUI just made and POST them to a URL you give it. No JSON, no auth headers, no GET, no fancy - just image bytes out to the internet. The use case is the part that matters: you want your generated image to end up somewhere that isn't your hard drive. A Telegram bot that saves your generations, a Discord webhook, a little Flask server you wrote to log outputs, a render farm. Wire this node in as the last stop on the graph and every finished image gets shoved at your endpoint automatically.
It's a two-line idea with a real bug in it, and the point of this page is saving you the hour I spent finding out.
What actually happens
The node is an output node with no outputs at all. You feed it an IMAGE tensor (anywhere the image already exists in your graph - a VAE Decode, a Load Image, whatever) and a URL, and when the queue runs it loops over every image in the batch and calls requests.post(url, data=img) once per image. Four images in a batch, four separate POSTs. No metadata is embedded, and the code comment helpfully explains the original plan was websocket-style binary sending - that's copy-pasted from ComfyUI's core save node, and the implementation didn't quite survive the trip.
One thing to know before you wire it in: IS_CHANGED returns the current time, so this node is always dirty. Every single queue run re-fires the request, even if nothing upstream changed. For a webhook that's usually what you want, but don't build it into a workflow you run a thousand times and then wonder why your endpoint got hammered.
The two inputs that matter
There are only two, and they're both required:
images- the IMAGE tensor you're sending.url- where to send it.
The trap is the url default. It ships as literally https:yourdomain... - not a working endpoint, and note the single slash. That's a placeholder, not a mistake you need to fix; it's just there so the field exists. You have to replace it, and the server on the other end has to actually exist. Posting to a random domain does nothing except fail.
The bug that will bite you
Here's the thing I verified by running the node's own code path: requests.post(url, data=img) passes a raw PIL Image object as the request body. Modern requests calls img.seek(0, 2) while measuring the body length, and PIL's seek() only accepts a frame number - so it throws TypeError: Image.seek() takes 2 positional arguments but 3 were given before a single byte is sent. On a current ComfyUI install (requests 2.x + Pillow 10), this node crashes every time. It probably worked once on some older combo, but today it doesn't.
The fix is a one-liner: serialize the image to bytes first.
import io, requests
buf = io.BytesIO()
img.save(buf, format="PNG")
requests.post(url, data=buf.getvalue(),
headers={"Content-Type": "image/png"})
That's the whole repair, and you'll want it anyway because the stock node sends no Content-Type and no filename - your receiving server has to read raw POST-body bytes and guess. With the fix, the request is a proper PNG upload.
Installing it
The README for this pack is empty - one commit, no install notes - so the standard path applies. Easiest is ComfyUI Manager: search comfy_http_request, install, restart. Or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/cuongloveit/comfy_http_request
# restart ComfyUI
That's genuinely all it needs. The whole pack is one node.py and an __init__.py; there's no requirements.txt, no model downloads, no heavy dependencies. It only uses requests and Pillow, both of which ComfyUI already ships.
The honest verdict
If the endpoint you're targeting can receive a plain image POST, this is a perfectly reasonable little node - after the one-line fix, it's the simplest thing that works, and "simplest thing that works" is high praise in the custom node ecosystem. If you need anything more - headers, JSON, multipart uploads, retries - skip it; you'd be fighting the node instead of using it, and a generic HTTP node will serve you better. And if the type error shows up in your console on first run, now you know exactly why.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| url | STRING | https:yourdomain... | — |
Outputs (0)
No outputs