comfy-portal-endpoint
This is a ComfyUI extension that provides additional API endpoints functionality, primarily designed to support Comfy Portal - a modern iOS client application for ComfyUI.
ComfyUI Portal Endpoint
REST API extension for ComfyUI that handles workflow management and UI → API format conversion. Built for Comfy Portal.
Conversion runs in a headless Chromium browser (via Playwright) that loads the real ComfyUI frontend — ensuring full compatibility with all node types including custom nodes.
Installation
cd ComfyUI/custom_nodes
git clone https://github.com/ShunL12324/comfy-portal-endpoint
Or search comfy-portal-endpoint in ComfyUI Manager.
Restart ComfyUI — the extension auto-installs all dependencies (Playwright, Chromium, system libs on Linux) on first startup.
API
All endpoints are under ComfyUI's HTTP server. Prefix with /api when using the default proxy.
| Endpoint | Method | Description |
|----------|--------|-------------|
| /cpe/health | GET | Browser status |
| /cpe/workflow/list | GET | List workflow files |
| /cpe/workflow/get?filename= | GET | Read a workflow file |
| /cpe/workflow/save | POST | Save a workflow file |
| /cpe/workflow/convert | POST | Convert UI format → API format |
| /cpe/workflow/get-and-convert?filename= | GET | Read + convert in one call (recommended) |
GET /cpe/health
Returns headless browser status: not_installed | not_initialized | initializing | ready | error
{ "status": "success", "browser": { "status": "ready" } }
GET /cpe/workflow/list
Lists all .json files in user/default/workflows/.
{
"status": "success",
"workflows": [
{ "filename": "my_workflow.json", "size": 4096, "modified": 1706000000.0 }
]
}
GET /cpe/workflow/get
| Param | Required | Description |
|-------|----------|-------------|
| filename | Yes | Path relative to workflows directory |
{ "status": "success", "filename": "my_workflow.json", "workflow": "<raw JSON string>" }
POST /cpe/workflow/save
| Field | Required | Description |
|-------|----------|-------------|
| workflow | Yes | Workflow JSON as string |
| name | No | Filename (auto-generated if omitted) |
POST /cpe/workflow/convert
Post the workflow JSON object directly as the request body.
| Status | Meaning |
|--------|---------|
| 200 | Success |
| 400 | Invalid body |
| 503 | Browser unavailable |
{
"status": "success",
"data": {
"workflow": {
"1": {
"inputs": { "ckpt_name": "model.safetensors" },
"class_type": "CheckpointLoaderSimple",
"_meta": { "title": "Load Checkpoint" }
}
}
}
}
First request ~5–15s (cold start). Subsequent ~1–2s.
GET /cpe/workflow/get-and-convert
Same as /cpe/workflow/convert but reads the file server-side. Takes filename query param. Response includes an additional filename field.
How It Works
Client → HTTP → ComfyUI PromptServer
↓
comfy-portal-endpoint
↓
Headless Chromium (page pool)
┌──────────┐ ┌──────────┐
│ Page 1 │ │ Page 2 │
│ ComfyUI │ │ ComfyUI │
│ Frontend │ │ Frontend │
└──────────┘ └──────────┘
Each conversion request acquires a page from the pool, reloads it for clean state, runs graphToPrompt() via page.evaluate(), and returns the page to the pool. Default pool size is 2 for concurrent requests.
First request takes ~5–15s (browser cold start). Subsequent requests ~1–2s.
Troubleshooting
| Issue | Fix |
|-------|-----|
| 503 on convert | pip install playwright && python -m playwright install chromium |
| Linux: missing .so libs | sudo python -m playwright install-deps |
| Docker: browser won't launch | Add RUN playwright install-deps chromium to Dockerfile |
| error in /cpe/health | Auto-recovers on next request. Check logs for details |
Known Limitations
- Not compatible with ComfyUI-Login or any extension that blocks/intercepts the ComfyUI frontend from loading. The headless browser needs full access to the frontend to perform workflow conversion. This is expected behavior and we have no plans to address it.
Changelog
v1.2.1
- Use ComfyUI native
app.loadGraphData+app.graphToPromptfor workflow conversion so subgraph workflows expand correctly (fixesclass_type: null/ UNKNOWN_NODE in Comfy Portal) - Keep legacy
__cpe_graphToPromptfallback for older ComfyUI frontends - Wait for the native API specifically before converting. The previous readiness check accepted either the native API or the legacy helper, and the legacy helper is available ~8s earlier — so the native path above never actually ran, and virtual nodes (
Note,Reroute) were emitted instead of dropped. Falling back to the legacy helper now logs a warning instead of happening silently - Stop reloading the page before every conversion. The frontend persists the open workflow and restores it asynchronously on load, which raced
loadGraphDataand could finish after it — so a conversion returned the previous workflow's graph, and every workflow converted to whatever was converted before it. Reloading is now only done on the retry path - Reject a converted graph containing nodes that aren't in the requested workflow. That failure returned wrong data rather than an error, which no caller could detect
v1.2.0
- Page pool for concurrent conversions (default 2 pages)
- Auto-install system deps on Linux (
playwright install-deps) - Auto-install pip via
get-pip.pyfallback - Robust process cleanup via driver PID
- Auto-replace broken pages in pool
- Fixed duplicate log output
v1.1.0
- Replaced WebSocket architecture with Playwright headless browser
- Works on headless servers, Docker, cloud VMs
- Auto-installs Playwright + Chromium on first startup
- Added
/cpe/healthendpoint and auto-recovery
v1.0.2
- Fixed array widget values, updated for ComfyUI frontend v1.9.10+
- Improved group node handling and virtual node support
License
MIT © 2025 Shun.L