Skip to main content

Introduction

The WebSocket API provides real-time, bidirectional communication between your client application and the ComfyUI server. Use it to monitor workflow execution, receive progress updates, and get preview images as they’re generated.

Connection Endpoint

Connect to the WebSocket endpoint using the following URL format:
ws://<server_address>/ws?clientId=<client_id>
server_address
string
required
The ComfyUI server address (e.g., 127.0.0.1:8188)
clientId
string
A unique identifier for your client session. If not provided, the server generates one automatically. Providing a clientId allows you to reconnect and resume an existing session.

Connection Example

Here’s how to establish a WebSocket connection using Python:
import websocket
import uuid

server_address = "127.0.0.1:8188"
client_id = str(uuid.uuid4())

ws = websocket.WebSocket()
ws.connect(f"ws://{server_address}/ws?clientId={client_id}")

# Listen for messages
while True:
    out = ws.recv()
    if isinstance(out, str):
        message = json.loads(out)
        print(f"Received: {message['type']}")
    else:
        # Binary data (preview images)
        print(f"Received binary data: {len(out)} bytes")

Initial Handshake

Server to Client: Initial Status

When you first connect, the server immediately sends a status message with the current queue state and your session ID:
{
  "type": "status",
  "data": {
    "status": {
      "exec_info": {
        "queue_remaining": 0
      }
    },
    "sid": "a1b2c3d4e5f6..."
  }
}

Reconnection Behavior

If you reconnect with an existing clientId and that client was executing a workflow, the server sends the current executing node:
{
  "type": "executing",
  "data": {
    "node": "3"
  }
}
The server removes any previous WebSocket connection with the same clientId when you reconnect, ensuring only one active connection per client.

Feature Flags Negotiation

ComfyUI supports feature flag negotiation between client and server. Send a feature_flags message as your first message after connecting:

Client to Server

{
  "type": "feature_flags",
  "data": {
    "supports_binary_preview": true,
    "supports_metadata": true
  }
}

Server Response

The server responds with its supported features:
{
  "type": "feature_flags",
  "data": {
    "binary_preview_images": true,
    "image_metadata": true
  }
}
Feature flag negotiation is optional but recommended for advanced clients that want to leverage server capabilities.

Message Types

WebSocket messages come in two formats:

JSON Messages

Text messages with the following structure:
{
  "type": "event_type",
  "data": { /* event-specific data */ }
}

Binary Messages

Binary messages contain preview images and other binary data. The format is:
[4 bytes: event type ID][remaining bytes: data]
The first 4 bytes represent the event type as a big-endian unsigned integer. See WebSocket Events for binary event types.

Tracking Workflow Execution

Here’s a complete example that queues a prompt and waits for execution to complete:
import websocket
import uuid
import json
import urllib.request

server_address = "127.0.0.1:8188"
client_id = str(uuid.uuid4())

def queue_prompt(prompt, prompt_id):
    p = {"prompt": prompt, "client_id": client_id, "prompt_id": prompt_id}
    data = json.dumps(p).encode('utf-8')
    req = urllib.request.Request(f"http://{server_address}/prompt", data=data)
    urllib.request.urlopen(req).read()

def wait_for_completion(ws, prompt_id):
    while True:
        out = ws.recv()
        if isinstance(out, str):
            message = json.loads(out)
            if message['type'] == 'executing':
                data = message['data']
                # Execution is done when node is None
                if data['node'] is None and data['prompt_id'] == prompt_id:
                    print(f"Execution complete for {prompt_id}")
                    break
                else:
                    print(f"Executing node: {data['node']}")
        else:
            # Binary preview image
            print(f"Received preview: {len(out)} bytes")

# Connect
ws = websocket.WebSocket()
ws.connect(f"ws://{server_address}/ws?clientId={client_id}")

# Queue a prompt
prompt_id = str(uuid.uuid4())
queue_prompt(your_workflow, prompt_id)

# Wait for completion
wait_for_completion(ws, prompt_id)

ws.close()

Error Handling

The WebSocket connection can fail for several reasons. Always implement proper error handling:
try:
    await ws.send_json(message)
except (aiohttp.ClientError, 
        aiohttp.ClientPayloadError, 
        ConnectionResetError, 
        BrokenPipeError, 
        ConnectionError) as err:
    print(f"WebSocket error: {err}")
    # Attempt reconnection

Best Practices

Generate a unique clientId (UUID) for each client instance to avoid conflicts and enable proper session management.
Always check if received data is a string (JSON) or binary data. Binary messages contain preview images.
When queuing prompts, include the client_id in the request and track prompt_id values to match execution events with your workflows.
Network issues can disconnect WebSocket connections. Implement exponential backoff reconnection with your original clientId.
Always close WebSocket connections when done, especially in environments with repeated calls (like web servers or Gradio apps).

Next Steps

WebSocket Events

Learn about all WebSocket event types and their data structures

Queue Prompt

Submit workflows for execution via the HTTP API

Build docs developers (and LLMs) love