ComfyUI's node canvas is where you design a generation. But once a workflow works, clicking "Queue Prompt" by hand does not scale — you want to generate a hundred product variations, render a batch of thumbnails from a spreadsheet, or plug image generation into a larger pipeline. The good news: ComfyUI is an API server. Everything the UI does, it does by POSTing JSON to a local endpoint, and you can drive it from Python.
This is a developer's guide to automating ComfyUI headlessly.
The Key Insight: The UI Is Just a Client
When you press Queue Prompt, the browser sends a JSON description of your graph to the ComfyUI server, which runs it and emits results. If you can produce that JSON and POST it, you can automate anything the UI can do — from a script, a cron job, or another service. The server also streams progress over a WebSocket, so you can watch a job and grab the output the moment it finishes.
Step 1: Export the Workflow API JSON
There are two JSON formats, and using the wrong one is the classic first mistake:
The normal "Save" format describes the visual graph (node positions, links) — for humans.
The "Save (API Format)" export (enable dev mode in ComfyUI settings, then use the API-format save) describes the graph as the server expects it: a flat map of node IDs to their class_type and inputs. This is the one you POST.
Export your working workflow in API format and open it — you will see each node keyed by ID, with inputs that are either literal values or [nodeId, outputIndex] references to other nodes.
Step 2: POST to /prompt
The core endpoint is POST /prompt. Send {"prompt": <the api-format graph>} and the server queues it, returning a prompt_id.
import json, urllib.request
with open("workflow_api.json") as f:
workflow = json.load(f)
# Override any input by editing the graph before sending:
workflow["6"]["inputs"]["text"] = "a red sports car at sunset" # positive prompt node
workflow["3"]["inputs"]["seed"] = 12345 # KSampler seed
payload = json.dumps({"prompt": workflow}).encode("utf-8")
req = urllib.request.Request("http://127.0.0.1:8188/prompt", data=payload)
resp = json.loads(urllib.request.urlopen(req).read())
print("queued:", resp["prompt_id"])
The node IDs ("6", "3") come straight from your API JSON — open it once to find which ID is your prompt, seed, and sampler. This override pattern is the heart of automation: load the template once, then loop, mutating a few inputs each iteration.
Step 3: Batch Generation
Now the payoff — drive it from a list, a CSV, or a database:
prompts = ["a red sports car", "a blue bicycle", "a green motorbike"]
for i, text in enumerate(prompts):
workflow["6"]["inputs"]["text"] = text
workflow["3"]["inputs"]["seed"] = 1000 + i
data = json.dumps({"prompt": workflow}).encode("utf-8")
urllib.request.urlopen(urllib.request.Request(
"http://127.0.0.1:8188/prompt", data=data))
That queues three jobs back to back. ComfyUI processes its queue in order and caches unchanged nodes, so only the parts of the graph affected by your edits re-run — batches are faster than the same prompts run cold.
Step 4: Retrieve the Output
For simple jobs, poll GET /history/{prompt_id} — once the job completes, the history entry lists the output images with their filenames and subfolders, which you fetch from GET /view?filename=....
For real-time control, open a WebSocket to /ws; the server streams execution progress and signals when your prompt_id finishes. ComfyUI ships two reference scripts — basic_api_example.py (polling) and websockets_api_example.py (streaming) — in its script_examples/ folder. Start from those rather than writing from scratch.
Running Headless
On a server with no display, launch ComfyUI as usual and it serves the API on 127.0.0.1:8188. A few operational notes:
Bind carefully. --listen exposes it beyond localhost — only do that inside a trusted network, and put authentication in front of it. The ComfyUI API has no built-in auth.
Manage the queue: GET /queue shows pending/running jobs; you can clear or interrupt via the API.
For a cleaner developer experience, ComfyScript lets you write workflows as Python instead of hand-editing node JSON — worth adopting once your automation grows beyond a few scripts.
Optimization Tips
Keep the server warm. Model loading dominates the first run; a long-lived server amortizes it across the whole batch.
Change as little as possible per iteration so ComfyUI's node cache can skip unchanged branches.
Parallelize the client, not the GPU. One GPU processes the queue serially; scale by adding GPUs/servers and load-balancing across their endpoints, not by hammering one instance.
Log the prompt_id and inputs for every job so outputs are reproducible and traceable.
Conclusion
Treating ComfyUI as an API turns it from an interactive toy into a production image engine. Export your graph in API format, POST it to /prompt, override a handful of node inputs in a loop, and collect results via /history or the WebSocket. Keep the server warm, mind the missing authentication, and reach for ComfyScript as your needs grow. This is the bridge between a workflow you designed by hand and a pipeline that renders while you sleep.
Downloadable Workflow & References
|

0 Comments