Thread Publish Video
Put a Video on Threads From the Graph — Once You Sort Out the Tunnel
- result
ThreadPublishVideo is the video counterpart to PublishThread: give it a video and some text, and it posts the whole thing to Threads from inside your workflow. If you're already generating short clips in ComfyUI and manually uploading them afterward, this is the node that closes that loop - with the same asterisk its image sibling carries, and then some. Videos are big files, so the "Threads has to be able to fetch it" problem isn't a footnote here, it's the main plot.
How it works
Like every node in this pack it reads token/thread_config.json first, so run StartWithLongLiveToken before you queue anything. Then it looks at video_path and decides what it is:
- Starts with
http://orhttps://→ treated as a network URL and used directly. - Anything else → treated as a local file, validated, copied into ComfyUI's output folder with a timestamped name (
thread_video_<timestamp>_<rand>_<name>.mp4), and turned into a URL off your base URL.
From there it creates a VIDEO media container on the Threads API, then polls its status every 20 seconds - up to 30 tries, so roughly 10 minutes - until it reports FINISHED, then publishes. The output result string comes back with the post URL, or a descriptive error if the container failed or timed out.
The inputs
text(required) - the caption, multi-line.video_path(required) - a local file path or an http(s) URL; the node auto-detects which.ComfyUIHttpsURL(optional) - your public HTTPS base URL, remembered intoken/url.jsonafter the first entry.
Output is a single result STRING. Wire it to a ShowText node to read the post URL or the error.
The tunnel is not optional for local videos
For PublishThread you can dodge the public-URL problem by pasting an external image URL. You can't really do that for video - the whole point here is uploading a local file. When the node copies your video into the output folder and builds https://.../api/view?filename=..., that URL has to be reachable by Threads' servers. If ComfyUIHttpsURL is still 127.0.0.1:8188, Threads can't fetch your video and the container will sit in limbo until the timeout. Set it to a real public HTTPS URL (ngrok is what the README suggests) before your first video run.
And because this is ComfyUI, the security bit is the same one the community keeps hammering: ComfyUI's API is unauthenticated by default, so exposing it via ngrok means anyone with the URL can run arbitrary workflows on your box. A dedicated throwaway instance is the sane approach for anything you tunnel.
Install
ComfyUI Manager → search ComfyUI-Thread → install → restart, or:
cd ComfyUI/custom_nodes/
git clone https://github.com/dseditor/ComfyUI-Thread
No model downloads. requirements.txt is a single line (threads_sdk) that the code never actually imports - it calls the Graph API directly - so there's nothing heavy to pull in.
Gotchas
- File size. Threads caps videos at 1GB. The node warns (but doesn't stop) when you exceed it - treat that warning as a "go re-encode" instruction, because Threads will reject the upload.
- The 10-minute polling window. If the container is still processing after 30 checks, you get a timeout message. Usually that means an oversized file, an incompatible format, or a video URL Threads couldn't reach. The README's checklist: file size, format compatibility, stable connection.
- "Local video file not found" - the path really is checked, so verify it exists and the file is readable before blaming the node.
- Extension checks are loose.
.mp4,.mov,.avi,.mkv,.flv,.wmv,.webmare recognized; anything else just prints a warning, and Threads' strict format requirements are the real judge. MP4/H.264 is the boring, reliable choice. - Threads' own rate limits (the README cites roughly 250 posts per 24 hours) apply here too - probably not your bottleneck, but worth knowing if you're running a bot.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | — | |
| video_path | STRING | — | |
| ComfyUIHttpsURLopt | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result | STRING | — |