The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "ComfyUI Image Generation Pipeline",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "generate-image",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-trigger",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
250,
300
]
},
{
"parameters": {
"jsCode": "// Extract prompt from webhook body or use default\nconst input = $input.first().json;\nconst prompt = input.body?.prompt || input.prompt || 'a beautiful sunset over mountains, highly detailed, 4k';\nconst negativePrompt = input.body?.negative_prompt || input.negative_prompt || 'blurry, low quality, distorted';\nconst seed = input.body?.seed || input.seed || Math.floor(Math.random() * 1000000000);\nconst steps = input.body?.steps || input.steps || 20;\nconst cfg = input.body?.cfg || input.cfg || 7;\nconst width = input.body?.width || input.width || 512;\nconst height = input.body?.height || input.height || 512;\n\n// ComfyUI API workflow format\n// This is a basic txt2img workflow - customize as needed\nconst comfyWorkflow = {\n "3": {\n "inputs": {\n "seed": seed,\n "steps": steps,\n "cfg": cfg,\n "sampler_name": "euler",\n "scheduler": "normal",\n "denoise": 1,\n "model": ["4", 0],\n "positive": ["6", 0],\n "negative": ["7", 0],\n "latent_image": ["5", 0]\n },\n "class_type": "KSampler",\n "_meta": { "title": "KSampler" }\n },\n "4": {\n "inputs": {\n "ckpt_name": "v1-5-pruned-emaonly.safetensors"\n },\n "class_type": "CheckpointLoaderSimple",\n "_meta": { "title": "Load Checkpoint" }\n },\n "5": {\n "inputs": {\n "width": width,\n "height": height,\n "batch_size": 1\n },\n "class_type": "EmptyLatentImage",\n "_meta": { "title": "Empty Latent Image" }\n },\n "6": {\n "inputs": {\n "text": prompt,\n "clip": ["4", 1]\n },\n "class_type": "CLIPTextEncode",\n "_meta": { "title": "CLIP Text Encode (Positive)" }\n },\n "7": {\n "inputs": {\n "text": negativePrompt,\n "clip": ["4", 1]\n },\n "class_type": "CLIPTextEncode",\n "_meta": { "title": "CLIP Text Encode (Negative)" }\n },\n "8": {\n "inputs": {\n "samples": ["3", 0],\n "vae": ["4", 2]\n },\n "class_type": "VAEDecode",\n "_meta": { "title": "VAE Decode" }\n },\n "9": {\n "inputs": {\n "filename_prefix": "n8n_generated",\n "images": ["8", 0]\n },\n "class_type": "SaveImage",\n "_meta": { "title": "Save Image" }\n }\n};\n\nreturn {\n json: {\n prompt: comfyWorkflow,\n original_prompt: prompt,\n negative_prompt: negativePrompt,\n seed: seed,\n steps: steps,\n cfg: cfg,\n width: width,\n height: height\n }\n};"
},
"id": "prepare-workflow",
"name": "Prepare ComfyUI Workflow",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
470,
300
]
},
{
"parameters": {
"method": "POST",
"url": "http://comfyui:8188/prompt",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ prompt: $json.prompt }) }}",
"options": {}
},
"id": "submit-to-comfyui",
"name": "Submit to ComfyUI",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
690,
300
]
},
{
"parameters": {
"jsCode": "const response = $input.first().json;\nconst promptId = response.prompt_id;\n\nif (!promptId) {\n throw new Error('No prompt_id received from ComfyUI');\n}\n\nreturn {\n json: {\n prompt_id: promptId,\n status: 'queued',\n check_count: 0,\n max_checks: 60,\n ...$input.first().json\n }\n};"
},
"id": "extract-prompt-id",
"name": "Extract Prompt ID",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
910,
300
]
},
{
"parameters": {
"amount": 2,
"unit": "seconds"
},
"id": "wait-node",
"name": "Wait 2 Seconds",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1130,
300
]
},
{
"parameters": {
"url": "=http://comfyui:8188/history/{{ $json.prompt_id }}",
"options": {}
},
"id": "check-history",
"name": "Check Generation Status",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1350,
300
]
},
{
"parameters": {
"jsCode": "const input = $input.first().json;\nconst promptId = $('Extract Prompt ID').first().json.prompt_id;\nconst historyData = input;\n\n// Check if our prompt_id exists in history and has outputs\nconst promptHistory = historyData[promptId];\n\nif (promptHistory && promptHistory.outputs) {\n // Find the SaveImage node output (node 9 in our workflow)\n const outputs = promptHistory.outputs;\n let images = [];\n \n for (const nodeId in outputs) {\n if (outputs[nodeId].images) {\n images = images.concat(outputs[nodeId].images);\n }\n }\n \n if (images.length > 0) {\n return {\n json: {\n status: 'completed',\n prompt_id: promptId,\n images: images,\n image_urls: images.map(img => \n `http://comfyui:8188/view?filename=${img.filename}&subfolder=${img.subfolder || ''}&type=${img.type || 'output'}`\n ),\n original_prompt: $('Extract Prompt ID').first().json.original_prompt,\n generation_params: {\n seed: $('Extract Prompt ID').first().json.seed,\n steps: $('Extract Prompt ID').first().json.steps,\n cfg: $('Extract Prompt ID').first().json.cfg\n }\n }\n };\n }\n}\n\n// Not ready yet - increment check count\nconst checkCount = ($('Extract Prompt ID').first().json.check_count || 0) + 1;\nconst maxChecks = $('Extract Prompt ID').first().json.max_checks || 60;\n\nif (checkCount >= maxChecks) {\n throw new Error(`Generation timed out after ${maxChecks} checks`);\n}\n\nreturn {\n json: {\n status: 'pending',\n prompt_id: promptId,\n check_count: checkCount,\n max_checks: maxChecks,\n original_prompt: $('Extract Prompt ID').first().json.original_prompt,\n seed: $('Extract Prompt ID').first().json.seed,\n steps: $('Extract Prompt ID').first().json.steps,\n cfg: $('Extract Prompt ID').first().json.cfg\n }\n};"
},
"id": "check-completion",
"name": "Check if Complete",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1570,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "condition-complete",
"leftValue": "={{ $json.status }}",
"rightValue": "completed",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-complete",
"name": "Generation Complete?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1790,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}",
"options": {}
},
"id": "respond-success",
"name": "Respond with Image",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
2050,
200
]
},
{
"parameters": {
"amount": 2,
"unit": "seconds"
},
"id": "wait-retry",
"name": "Wait and Retry",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
2050,
400
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ error: 'Generation failed', details: $json }) }}",
"options": {
"responseCode": 500
}
},
"id": "respond-error",
"name": "Respond with Error",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
2270,
500
]
},
{
"parameters": {},
"id": "no-op",
"name": "No Operation",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
2270,
400
]
}
],
"connections": {
"Webhook Trigger": {
"main": [
[
{
"node": "Prepare ComfyUI Workflow",
"type": "main",
"index": 0
}
]
]
},
"Prepare ComfyUI Workflow": {
"main": [
[
{
"node": "Submit to ComfyUI",
"type": "main",
"index": 0
}
]
]
},
"Submit to ComfyUI": {
"main": [
[
{
"node": "Extract Prompt ID",
"type": "main",
"index": 0
}
]
]
},
"Extract Prompt ID": {
"main": [
[
{
"node": "Wait 2 Seconds",
"type": "main",
"index": 0
}
]
]
},
"Wait 2 Seconds": {
"main": [
[
{
"node": "Check Generation Status",
"type": "main",
"index": 0
}
]
]
},
"Check Generation Status": {
"main": [
[
{
"node": "Check if Complete",
"type": "main",
"index": 0
}
]
]
},
"Check if Complete": {
"main": [
[
{
"node": "Generation Complete?",
"type": "main",
"index": 0
}
]
]
},
"Generation Complete?": {
"main": [
[
{
"node": "Respond with Image",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait and Retry",
"type": "main",
"index": 0
}
]
]
},
"Wait and Retry": {
"main": [
[
{
"node": "Check Generation Status",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"meta": {
"templateCredsSetupCompleted": true
},
"versionId": "1",
"triggerCount": 0,
"tags": [
{
"name": "ComfyUI",
"id": "1"
},
{
"name": "Image Generation",
"id": "2"
},
{
"name": "AI Stack",
"id": "3"
}
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
How this works
Generate high-quality images effortlessly from text prompts using this ComfyUI pipeline, saving hours of manual design work for creators and marketers. Ideal for content teams needing quick visuals for social media or prototypes without investing in complex tools. The process starts with a webhook trigger that sends your prompt to ComfyUI via an HTTP request, followed by polling for completion to deliver the final image seamlessly.
Use this workflow for on-demand image creation integrated with chatbots or forms, such as producing custom artwork during customer interactions. Avoid it for real-time applications requiring sub-second responses, as the built-in wait and status checks add slight delays. Common variations include adding post-processing nodes for resizing or integrating with storage services like Google Drive for automatic uploads.
About this workflow
ComfyUI Image Generation Pipeline. Uses httpRequest, respondToWebhook, noOp. Webhook trigger; 12 nodes.
Source: https://github.com/Zie619/n8n-workflows/blob/main/ai-stack/workflows/comfyui-image-generation.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Portfolio Orchestrator. Uses httpRequest. Webhook trigger; 59 nodes.
jump-section: Comment Fix Pipeline. Uses httpRequest. Webhook trigger; 24 nodes.
GitHub Issues Router (Linear / Jira / ClickUp). Uses stickyNote, httpRequest, respondToWebhook. Webhook trigger; 23 nodes.
Form to CRM Lead Router (Pipedrive / HubSpot / Salesforce). Uses stickyNote, httpRequest, respondToWebhook. Webhook trigger; 22 nodes.
Calendly to CRM Sync (Pipedrive / HubSpot / Salesforce). Uses stickyNote, httpRequest, respondToWebhook. Webhook trigger; 22 nodes.