Nodes/CCollins' CiviScribe/CiviScribe - Save Image for Civitai
ComfyUI Node

CiviScribe - Save Image for Civitai

The save node that makes Civitai actually read your generation settings

By chriscollins500·Created 29 days ago·Updated 2 days ago· 2
CiviScribe - Save Image for Civitai
  • images
  • Images
filename_prefixComfyUI
output_formatpng
jpeg_quality100
jpeg_alpha_background#FFFFFF
webp_losslesstrue
webp_quality100
write_sidecar_jsonfalse
include_workflowtrue
include_civitai_manifesttrue
enable_civitai_lookupfalse
preferred_primary_model_air
hashing_modecached_or_fast
lookup_timeout_seconds4.0
lookup_cache_resultstrue
advanced_manual_identities_enabledfalse
manual_resource_identities_json[]
positive_prompt_override
negative_prompt_override

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 IMAGE output. Non-negotiable, the only required input besides defaults.
  • output_format - png, jpeg, or webp. 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.

CategoryCCollins/CiviScribe

Inputs (19)

NameTypeDefaultDescription
imagesIMAGEImages to save.
filename_prefixSTRINGComfyUIFilename 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_formatCOMBOpngImage format. PNG and WebP are lossless by default; JPEG is lossy.
jpeg_qualityINT1001–100JPEG fidelity. 100 is the maximum-fidelity default.
jpeg_alpha_backgroundSTRING#FFFFFFRGB background used when JPEG must flatten transparent pixels.
webp_losslessBOOLEANtrueUse decoded-pixel-preserving WebP encoding.
webp_qualityINT1000–100WebP compression effort or lossy quality.
write_sidecar_jsonBOOLEANfalseAlso write deterministic metadata JSON beside each saved image.
include_workflowBOOLEANtrueEmbed 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_manifestBOOLEANtrueInclude the structured Civitai manifest in rich metadata and sidecars.
enable_civitai_lookupBOOLEANfalseAsk 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_airSTRINGOptional AIR, Civitai model URL, or model-version ID that pins the active primary model identity.
hashing_modeCOMBOcached_or_fastcached_only reads no model bytes; cached_or_fast uses caches and fast hashes; full may read whole model files.
lookup_timeout_secondsFLOAT4.01–30Maximum Civitai lookup wait. Saving continues after a timeout.
lookup_cache_resultsBOOLEANtrueStore successful identities locally so later saves can resolve them without another request.
advanced_manual_identities_enabledBOOLEANfalseEnable the advanced JSON mapping for pinning identities of multiple active resources.
manual_resource_identities_jsonSTRING[]Advanced JSON list of explicit resource identity mappings. Invalid data is reported safely and never blocks image saving.
positive_prompt_overrideoptSTRINGConnect 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_overrideoptSTRINGConnect 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)

NameTypeDescription
ImagesIMAGEOriginal image tensor passed through unchanged.