Save Image w/ Metadata Universal
The save node that makes Civitai actually read your ComfyUI images
- images
- extra_metadata
- images
The default SaveImage node embeds your full workflow in the PNG, and that's genuinely useful - drag the image back onto the canvas and the graph rebuilds. But it never writes the flat A1111-style parameters string with model and LoRA hashes that Civitai's auto-detector keys on. So you upload your image, and the "used resources" section is empty, and you're typing checkpoint names in by hand. That's the exact problem Save Image w/ Metadata Universal exists to kill: swap it in, and your PNGs carry a proper generator card that Civitai reads, with the workflow intact alongside it.
It's the flagship node of the ComfyUI_SaveImageWithMetaDataUniversal pack, an extensive rework of nkchocoai's classic ComfyUI-SaveImageWithMetaData that adds "universal" support for custom node packs. The author (xxmjskxx on GitHub, mossfoul on Reddit) is upfront about being an amateur coder leaning on Copilot, but the pack is well-kept, actively patched, and people do run it in production - it handles SD1.5/SDXL/FLUX/QWEN/WAN, GGUF, and Nunchaku.
How it actually captures the metadata
Here's the neat trick: it doesn't make you wire a bunch of metadata inputs. The node monkeypatches ComfyUI's execution module (the pre_execute / pre_get_input_data hooks) to record the prompt graph as it runs, then traces backward from the save node to find the sampler, loaders, and encoders that actually produced the image. Values are pulled out of the inputs of whatever nodes it finds - no manual connecting required. LoRAs are detected from single or stack loaders and inline <lora:name:strength> tags, embeddings get resolved and hashed, and it even handles dual-encoder setups like Flux's T5 + CLIP.
Model hashes are computed once and cached in .sha256 sidecar files next to your models, so the first save is slow-ish and every one after is fast. That's a small detail that saves you a lot of time when you have a hundred GB of checkpoints.
The inputs that matter
images- wire your VAE decode output here. This is the only required connection.filename_prefix- a template, not just a name. It accepts%seed%,%width%,%height%,%pprompt%,%nprompt%,%model%, and%date%(with custom patterns like%date:yy-MM-dd%), and a slash in the prefix creates subfolders, soportraits/%model%/%seed%is fair game.sampler_selection_method-Farthest,Nearest, orBy node ID. This picks which earlier sampler's settings get recorded, which matters if your workflow has more than one.file_format-png,jpeg, orwebp. PNG retains the full workflow; the others are delivery formats.
Then the optional toggles that matter for Civitai: civitai_sampler normalizes sampler naming for import fidelity, guidance_as_cfg records FLUX-style guidance under "CFG scale" (leave it off and Civitai sees a CFG value that was never set), and lora_strengths_in_prompt appends A1111-style LoRA tags to the prompt text so Civitai can read their strengths. include_lora_summary adds a compact LoRAs: line. extra_metadata plugs in the output of the Create Extra MetaData node.
The output is an images socket that passes the batch through, so you can chain other nodes after saving.
Installing it
No models to download, no heavy deps - the pack just needs Pillow, NumPy, and piexif, which a normal ComfyUI install already has. ComfyUI Manager has it (search "Save Image with Metadata Universal"), or:
cd <ComfyUI directory>/custom_nodes
git clone https://github.com/xxmjskxx/ComfyUI_SaveImageWithMetaDataUniversal.git
Restart ComfyUI, and the node appears under the SaveImageWithMetaDataUniversal category.
Where people get burned
The JPEG thing. JPEG metadata lives in a single ~64KB EXIF segment, so big workflows don't fit. The node handles this with staged fallback - reduced-exif → minimal → com-marker - and appends a Metadata Fallback: <stage> marker to the parameter string when it trims. If your JPEG comes out missing fields, that's not a rules bug; use PNG or lossless WebP for archival, or nudge max_jpeg_exif_kb up toward its 64KB cap.
Also: two-stage pipelines (say a Qwen→Wan video workflow) only record one stage's sampler, whichever sampler_selection_method picks - multi-stage recording isn't supported yet. And after you update the pack or add new nodes, you should re-run the Metadata Rule Scanner + Save Custom Metadata Rules flow so your capture rules stay current; the node logs a [Metadata Loader] warning if your saved rules are stale.
One privacy footnote worth knowing: this node writes more metadata than the default, including exact model names and hashes. That's the point for sharing, but it's also your full prompt and pipeline traveling with every image. Same deal as any rich-metadata saver - just be aware before you post.
Inputs (18)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| filename_prefix | STRING | ComfyUI | Sets the output filename prefix and can also include subdirectories, so values like folder/image will save into a folder under your output directory. You can use %seed%, %width%, %height%, %pprompt%, %nprompt%, %model%, and %date% in the path or filename. Date can accept any variety of the yyyyMMddhhmmss format, e.g. %date:yy-MM-dd%. |
| sampler_selection_method | COMBO | How to choose which earlier sampler node's settings to record: farthest, nearest, or by node id (see sampler_selection_node_id). | |
| sampler_selection_node_id | INT | 00–999999999 | When method is 'By node ID', this specifies which sampler node to treat as authoritative for Steps/CFG/etc. |
| file_format | COMBO | Image format for output. PNG retains full metadata; JPEG/WebP may strip or re-encode some fields. | |
| lossless_webpopt | BOOLEAN | true | If using WebP, toggles lossless mode (ignores quality slider). |
| qualityopt | INT | 1001–100 | Quality for lossy formats (JPEG/WebP lossy). 100 = best quality, larger files. |
| max_jpeg_exif_kbopt | INT | 601–64 | Maximum EXIF payload (KB) to attempt embedding in JPEG. Practical hard cap ~64KB due to single APP1 (EXIF) segment size; larger blocks are rejected or stripped. If exceeded, fallback stages apply: reduced-exif (parameters only) -> minimal (trimmed) -> com-marker. You should have no issues writing smaller workflows and metadata, but should use PNG/WebP for full workflow storage with larger workflows and metadata. |
| save_workflow_jsonopt | BOOLEAN | false | Save the workflow as a JSON file alongside the image. |
| add_counter_to_filenameopt | BOOLEAN | true | Automatically append an incrementing counter to avoid overwriting existing files with the same prefix. |
| civitai_sampleropt | BOOLEAN | false | Add a Civitai-compatible sampler notation (if enabled) for better import fidelity on Civitai. |
| guidance_as_cfgopt | BOOLEAN | false | When enabled, record 'Guidance' value under 'CFG scale' and suppress separate Guidance field. Makes guidance with models like FLUX Civitai-compatible (if enabled). |
| extra_metadataopt | EXTRA_METADATA | Additional metadata key-value pairs from the Create Extra MetaData node to include in the saved image. | |
| save_workflow_imageopt | BOOLEAN | true | If disabled, the workflow data will not be saved in the image metadata. |
| include_lora_summaryopt | BOOLEAN | false | Include a compact aggregated LoRAs summary line (set False to list only individual Lora_X entries). |
| suppress_missing_class_logopt | BOOLEAN | true | Hide the informational log about missing classes that triggers a user JSON merge ('[Metadata Loader] Missing classes in defaults+ext ...'). Can be useful to disable if debugging problematic nodes |
| model_hash_logopt | COMBO | none | Artifact hashing log: filename=short, path=full, detailed=resolution+sidecar, debug=+candidates+full hash. |
| lora_strengths_in_promptopt | BOOLEAN | false | When enabled, A1111-style LoRA designations (e.g. <lora:name:strength>) are appended to the positive prompt text and Lora hashes are included in metadata so that Civitai can recognize LoRA strengths. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |