CiviScribe - Save Image for Civitai
The save node that makes Civitai actually read your generation settings
- images
- Images
ComfyUI's stock SaveImage node has one annoying gap: it writes the ComfyUI workflow graph into the PNG, but not the flat A1111-style parameters block that Civitai's uploader actually auto-detects to link your model, LoRAs, and settings. So you render something great, upload it, and Civitai shrugs - no model linked, no prompt, nothing. CiviScribe is the node that fixes exactly that. It's a drop-in SaveImage replacement from the chriscollins500/ccollins-civiscribe pack that writes both dialects of metadata plus a structured Civitai manifest, so the upload page recognizes your generation without you typing any of it by hand.
You don't need a Civitai account, token, or API key to use it. The name might suggest a cloud service, but it's a lie in the best way: CiviScribe saves everything locally and only touches the network if you flip one optional setting.
How it works
Under the hood it's smarter than the save nodes that just dump every loader on the canvas into the metadata. CiviScribe traces the active path - it walks backward from the images input through the nodes that actually fed the saved image, ignoring loaders sitting elsewhere in your graph that didn't contribute. That means the model and LoRAs recorded are the ones that made this picture, which is exactly what Civitai needs to link resources correctly.
Along that path it collects the prompt, seed, steps, sampler, scheduler, CFG, denoise, and size, then hashes the model files (AutoV1, AutoV2, AutoV3, or full SHA-256 depending on your hashing mode) so Civitai can match them to its catalog. The honest part is the part I like: if it can't prove a resource's identity, it leaves it unresolved rather than guessing from a filename. And it's pixels-first - if metadata writing fails at every level, it still saves the image rather than throwing the whole run away.
The inputs that matter
You wire this node in exactly like SaveImage, at the end of the graph:
- images - connect your final
IMAGEoutput. Non-negotiable, the only required input besides defaults. - output_format -
png,jpeg, orwebp. PNG is lossless and the only one that carries the reloadable ComfyUI workflow, so it's the right default for anything you might want to reopen later. - filename_prefix - supports ComfyUI's
%date:yyyy-MM-dd%and%Node.widget%tokens, plus handy CiviScribe aliases like%model%,%seed%,%sampler%,%width%,%height%. A pattern like%date:yyyy-MM-dd%/%date:hhmmss%_%model%gives you dated subfolders and readable names. - include_workflow and include_civitai_manifest - both default to on; they're what make the PNG rich. Turn them off if you want leaner files.
- enable_civitai_lookup - off by default, and leave it off for normal saving. Turn it on and CiviScribe sends only hashes or explicit model-version IDs to Civitai's API to resolve unknown resources; it never uploads the image or your prompt.
- positive_prompt_override / negative_prompt_override - the only optional inputs you'll likely touch, and only if an LLM or wildcard node builds your prompt at runtime. Since that text doesn't exist in the queued graph, you feed the final string here so the metadata is still truthful. It changes metadata only, never generation.
The output is Images - the original tensor passed through unchanged, so you can chain another node after saving if you ever want to.
Installing it
Easiest route is ComfyUI Manager: search for CiviScribe, open the pack card, install, restart. Or do it manually in your custom_nodes folder:
cd ComfyUI/custom_nodes
git clone https://github.com/chriscollins500/ccollins-civiscribe.git
cd ccollins-civiscribe
python -m pip install .
Use the same Python that launches ComfyUI, then restart. Dependencies are light - just Pillow, httpx, and numpy - and there are no model downloads. The catch: this is a native ComfyUI V3 node, so it needs current ComfyUI (Desktop release, >= 0.33.1) and Python 3.12 or newer. If you're on an older ComfyUI install, the node simply won't appear - update first.
Gotchas worth knowing
- JPEG and WebP can't carry the reloadable workflow. They get the A1111/Civitai metadata in EXIF, but the ComfyUI graph is PNG-only. Save PNG as your master.
- Unresolved resources stay unresolved until you enable lookup or pin a preferred AIR/model-version ID. That's by design - no filename guessing - but it means you sometimes have to flip the switch for perfect auto-linking.
- It saves, it doesn't upload. You still drag the file onto Civitai yourself. CiviScribe just makes sure the paperwork travels with the pixels.
If your workflow's auto-detection misses something, the README's final-prompt-override guide and the interface's context-sensitive controls cover the edge cases. For a "save the image and make it shareable" node, that's a lot of engineering in one pack - and it means one less thing to hand-type before you hit upload.
Inputs (19)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | Images to save. | |
| filename_prefix | STRING | ComfyUI | Filename or safe subfolder pattern. Supports ComfyUI %date:FORMAT% and %Node name.widget_name% replacements; %year%, %month%, %day%, %hour%, %minute%, %second%, %width%, %height%, and %batch_num%; plus CiviScribe %model%, %seed%, and %sampler% aliases. |
| output_format | COMBO | png | Image format. PNG and WebP are lossless by default; JPEG is lossy. |
| jpeg_quality | INT | 1001–100 | JPEG fidelity. 100 is the maximum-fidelity default. |
| jpeg_alpha_background | STRING | #FFFFFF | RGB background used when JPEG must flatten transparent pixels. |
| webp_lossless | BOOLEAN | true | Use decoded-pixel-preserving WebP encoding. |
| webp_quality | INT | 1000–100 | WebP compression effort or lossy quality. |
| write_sidecar_json | BOOLEAN | false | Also write deterministic metadata JSON beside each saved image. |
| include_workflow | BOOLEAN | true | Embed the sanitized ComfyUI API prompt graph and UI workflow graph. Turn this off to omit both graph payloads from the image and sidecar. |
| include_civitai_manifest | BOOLEAN | true | Include the structured Civitai manifest in rich metadata and sidecars. |
| enable_civitai_lookup | BOOLEAN | false | Ask Civitai to identify active resources from hashes. Only hashes or a model-version ID are sent; images, prompts, workflows, and paths are not. |
| preferred_primary_model_air | STRING | Optional AIR, Civitai model URL, or model-version ID that pins the active primary model identity. | |
| hashing_mode | COMBO | cached_or_fast | cached_only reads no model bytes; cached_or_fast uses caches and fast hashes; full may read whole model files. |
| lookup_timeout_seconds | FLOAT | 4.01–30 | Maximum Civitai lookup wait. Saving continues after a timeout. |
| lookup_cache_results | BOOLEAN | true | Store successful identities locally so later saves can resolve them without another request. |
| advanced_manual_identities_enabled | BOOLEAN | false | Enable the advanced JSON mapping for pinning identities of multiple active resources. |
| manual_resource_identities_json | STRING | [] | Advanced JSON list of explicit resource identity mappings. Invalid data is reported safely and never blocks image saving. |
| positive_prompt_overrideopt | STRING | Connect the final positive prompt string actually sent to the active text encoder when an LLM, wildcard, switch, or custom node creates it at runtime. This changes metadata only, not generation. | |
| negative_prompt_overrideopt | STRING | Connect the final negative prompt string actually sent to the active text encoder when a runtime node builds it dynamically. This changes metadata only, not generation. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| Images | IMAGE | Original image tensor passed through unchanged. |