Hailuo 2.3 Pro Image to Video
Animate a still without leaving the graph
- image_url
- video
- url
- all_urls_json
- task_id
- raw_json
- credits_consumed
- credits_left
Image-to-video is the workflow that made hosted video models worth paying for: you already made the still - with your checkpoint, your LoRA, your ControlNet stack - and now you want eight seconds of it moving. Hailuo 2.3 Pro is MiniMax's higher tier for exactly that. This node takes your IMAGE straight off the canvas, uploads it, and returns a VIDEO you can keep wiring.
What it is, and why the Pro label matters
MiniMax is the Shanghai lab behind the Hailuo service; its generation line stayed closed and API-first for years before H3 opened weights in August 2026. Hailuo 2.3 Pro is the quality tier of the 2.3 image-to-video pair. The Standard node next to it in the same folder takes the same inputs - the difference is fidelity and how well fine motion holds together, not features. Pay for Pro on the shots that end up in the edit; iterate on Standard.
Since there are no weights, "install" means an API key and a network connection. If you're allergic to that, the local answer is Wan 2.2 on your own GPU - slower, cheaper per clip, and yours. This node is for when you want the motion quality without the hardware.
The inputs
prompt (required, up to 5000 characters) describes the animation, not the image. This is where people flounder: the still already decided the subject, so spend the prompt on what happens - "she turns her head to the left, sleeve fabric sways, camera slowly pushes in" - rather than re-describing the kimono.
image_url (required) is a real IMAGE socket. Wire any image-producing node into it. The pack converts the tensor to PNG and uploads it to KIE before the job is submitted; you never paste a URL.
resolution is 768P or 1080P, default 768P. duration is 6 or 10 seconds. And the one combination the help text calls out: 10 seconds is not supported at 1080P. Pick one or the other, or you'll get a provider-side rejection after your image has already been uploaded.
nsfw_checker defaults to false (KIE's filtering off). timeout_seconds defaults to 1200 - 20 minutes of polling, which is generous but not infinite; the Pro tier queues in busy hours.
No seed and no aspect-ratio control. The output shape follows your input image, and a rerun is a new roll.
Outputs
video is the result as a ComfyUI VIDEO - feed it to a combine/save node, or to another node that takes video (the pack has a Topaz upscale and a lip-sync node that both eat VIDEO). Then url, all_urls_json, task_id, raw_json, and the two floats worth watching if you're iterating: credits_consumed and credits_left. The node prints the receipt on the widget too.
Results are archived locally under ComfyUI/output/KIE-Results/videos/ with content-hashed filenames, which is the pack's answer to KIE's result URLs being temporary. If a workflow's node shows a video after a restart, that's why it still works.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/felipederosilva/ComfyUI-KIE-Nodes-Next
cd ComfyUI-KIE-Nodes-Next
pip install -r requirements.txt
Restart ComfyUI. Dependencies are requests, Pillow, numpy, PyYAML - no checkpoints, no VRAM, nothing to put in models/. dist/ in the repo also has a one-click Windows installer. ComfyUI Manager may or may not list it yet; the README still describes the registry route as upcoming, so don't assume it's there.
Then set the key once: Settings → KIE.ai Nodes Next → Connection, paste, and wait for the ✅ CONNECTED status. Headless installs can use the KIE_API_KEY environment variable instead - and be aware that if that variable is set, it wins over the key you saved in settings. A stale export in a Docker compose file is the usual cause of "but I pasted the new key."
Troubleshooting
Task failed with a content-policy message is the most common one, and it happens after upload, so you can't predict it from the node alone. Rework the prompt; nsfw_checker=false turns off KIE's own filter, not the model's judgment.
"Timed out waiting for KIE task …" - you were already charged; the job keeps running. Copy the task_id out of the error and poll it with the Task Status node rather than re-queueing blind.
Nothing happens when you queue again - you changed nothing, so ComfyUI served the cached output. That's a free rerun, not a broken node. Change the prompt or the image to submit a new paid job.
Upload rejected. KIE's docs for this family want JPEG/PNG/WebP, at least 300px on the short side, under 10MB, and an aspect ratio between roughly 1:2.5 and 2.5:1. A 4096×4096 outpaint or an extreme panorama can fail before generation starts.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| prompt | STRING | A graceful geisha performs a traditional Japanese dance indoors. She wears a luxurious red kimono with golden floral embroidery, white obi belt, and white tabi socks. Soft and elegant hand movements, expressive pose, sleeves flowing naturally. Scene set in a Japanese tatami room with warm ambient lighting, shoji paper sliding doors, and cherry blossom branches hanging in the foreground. Cinematic, soft depth of field, high detail fabric texture, hyper-realistic, smooth motion. | Text prompt describing the desired video animation (Max length: 5000 characters) |
| image_url | IMAGE | — | |
| durationopt | COMBO | 6 | The duration of the video in seconds. 10 seconds videos are not supported for 1080p resolution. |
| resolutionopt | COMBO | 768P | The resolution of the generated video. |
| nsfw_checkeropt | BOOLEAN | false | Defaults to false. You can set it to false based on your needs. If set to false, our content filtering will be disabled, and all results will be returned directly by the model itself. Note: There is no guarantee that everything can be filtered out; if you are not satisfied with the results, you will need to make your own arrangements. |
| timeout_secondsopt | INT | 120030–7200 | — |
| callback_urlopt | STRING | Optional KIE callback URL. Leave empty for normal ComfyUI use. |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| video | VIDEO | — |
| url | STRING | — |
| all_urls_json | STRING | — |
| task_id | STRING | — |
| raw_json | STRING | — |
| credits_consumed | FLOAT | — |
| credits_left | FLOAT | — |