OpenRouter LLM Node (Text/Multi-Image/PDF/Chat)
Every LLM on the Internet, One ComfyUI Node (and Your GPU Never Lifts a Finger)
- pdf_data
- Output
- image
- Stats
- Credits
This node is a gateway, not a model. Drop it into a workflow, hand it an OpenRouter API key, and suddenly the model dropdown offers you three hundred-plus LLMs - GPT, Claude, Gemini, Llama, whatever's live on OpenRouter this week - with zero local model files, zero VRAM, and no transformers version hell. You want a prompt rewritten mid-graph, a reference image described, a PDF summarized, or an image generated via Google's Nano-Banana, all without a local LLM install? That's the pitch. Given how much ComfyUI pain is downloading models and fixing dependencies, a node whose entire install is two pip packages feels almost like cheating.
How it works
Under the hood it's a thin, synchronous client for OpenRouter's chat completions API. When you run the workflow it POSTs your system prompt, user message, and any attached images (base64-encoded) or PDF text to https://openrouter.ai/api/v1/chat/completions, then waits for the text back. The model list isn't hardcoded - it's fetched live from OpenRouter's /api/v1/models endpoint on first load and cached for an hour, which is why the dropdown always seems to have things you've never heard of. It uses tiktoken for honest token counting and hits the credits endpoint so it can show you your remaining balance. That's the whole mechanism: API calls, no inference. One catch - it's synchronous, so a slow or thinking-heavy model blocks the graph until it returns (the request_timeout defaults to 120 seconds). Don't put it on the critical path mid-pipeline if you can avoid it.
The inputs that matter
You can ignore most of the surface here and it'll still work. The ones you'll actually set:
- api_key - your OpenRouter key. Leave it blank and read the security section below.
- system_prompt and user_message_box - the prompt. There's also
user_message_input, which lets you wire the message in from another node instead of typing it. - model - the giant live dropdown.
cheapest(routes via:floor) is on by default,fastest(:nitro) is off,web_search(:online) is a paid extra at $4 per 1000 queries. - reasoning_effort -
autosends no override;minimalthroughxhighrequest more thinking where the model supports it. Handy for forcing a cheap model to actually reason instead of slapping out a first draft.
Everything else is either for image generation (see below) or nice-to-have: temperature, seed, request_timeout, and chat_mode, which persists conversation history into a chats/ folder for multi-turn conversations across runs (a fresh session starts after an hour of inactivity, and manage_chats.py lists, exports, and cleans them up).
The node has four outputs. Output (STRING) is the LLM's text - wire it to a ShowText node (pythongosssss/ComfyUI-Custom-Scripts or any text display) to see it. image (IMAGE tensor) is empty unless you used an image-capable model like google/gemini-2.5-flash-image-preview; then it drops the generated image straight into the graph for further processing. Stats and Credits just report tokens per second and your remaining balance.
Installing it
ComfyUI Manager: search for "ComfyUI OpenRouter Node" and click install. Or the manual way:
cd ComfyUI/custom_nodes
git clone https://github.com/gabe-init/ComfyUI-Openrouter_node
pip install -r requirements.txt # just tiktoken and Pillow
Restart ComfyUI. No model downloads - that's the whole point. The only external requirement is an OpenRouter account with a few dollars of credit on it.
The trap: your API key is in the PNG
Here's where people get burned. ComfyUI embeds the entire workflow - every field, including your api_key - into the PNG metadata of anything you save. The workflow-sharing culture that makes "drag the image back in and it rebuilds" so great is exactly what hands your key to anyone you share an image with. This got real enough that a malicious "LLM vision" node in this ecosystem ended in a federal prosecution, so treat any key typed into a node as exposed.
The fix is easy: don't type the key. Create openrouter_api_key.json in the node directory with {"api_key": "your_key_here"}, or export LLM_KEY as an environment variable, and leave the UI field blank - the node resolves the key in that order. chmod 600 that JSON on Linux/macOS. And if you ever did type it in, clear the field before saving the workflow, because that value is baked in already.
Other real-world snags, all from the README: model list not loading means a network or key problem; slow responses mean flip on fastest; and image generation only triggers if the model supports image output and your prompt reads like a generation request ("generate", "create", "draw"…) - the node detects that by keyword. The extended aspect ratios (1:4, 4:1, 8:1) are Nano-Banana-2-only.
For a ComfyUI newcomer it's the least intimidating way to get real LLM intelligence into your graph - just guard the key like a credit card, because in workflow metadata, it effectively is.
Inputs (17)
| Name | Type | Default | Description |
|---|---|---|---|
| api_key | STRING | — | |
| system_prompt | STRING | You are a helpful assistant. | — |
| user_message_box | STRING | Hello, how are you? | — |
| model | COMBO | 338 options: ai21/jamba-large-1.7, aion-labs/aion-2.0, aion-labs/aion-3.0, aion-labs/aion-3.0-mini, aion-labs/aion-rp-llama-3.1-8b, allenai/olmo-3-32b-think, +332 | |
| web_search | BOOLEAN | false | — |
| cheapest | BOOLEAN | true | — |
| fastest | BOOLEAN | false | — |
| aspect_ratio | COMBO | auto | 15 options: auto, 1:1 (1024x1024), 2:3 (832x1248), 3:2 (1248x832), 3:4 (864x1184), 4:3 (1184x864), +9 |
| image_resolution | COMBO | 1K | 3 options: 1K, 2K, 4K |
| reasoning_effort | COMBO | auto | 7 options: auto, none, minimal, low, medium, high, +1 |
| seed | INT | 00–18446744073709550000 | — |
| temperature | FLOAT | 1.000–2 | — |
| pdf_engine | COMBO | auto | 3 options: auto, mistral-ocr, pdf-text |
| chat_mode | BOOLEAN | false | — |
| request_timeout | INT | 1201–3600 | — |
| pdf_dataopt | * | — | |
| user_message_inputopt | STRING | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| Output | STRING | — |
| image | IMAGE | — |
| Stats | STRING | — |
| Credits | STRING | — |