Prompt Tag Cleanup
Tidy a prompt's tags — dedupe, sort, cap — without mangling emphasis
- text
- tags
- tag_strings
- count
- removed
Prompts arrive messy. A concatenated pile of tags has duplicates, stray commas from unconnected inputs, and line breaks that become part of a tag if you're not careful. Prompt Tag Cleanup splits that mess into tags, drops what you don't want, optionally sorts and caps the list, and joins it back up - while correctly treating emphasis like (tag:1.4) as the same tag as the plain spelling. That last bit is the part that separates it from a naive string dedupe.
It's the polite-bouncer node: most of what it does is invisible until you wire it into the path and realize your prompt stopped growing a copy of every tag on every concat. If you build prompts from multiple Text Concatenate branches - a subject block plus a style block plus a quality block - you've almost certainly shipped duplicates without noticing, because the eye skips repeated words. This node notices.
The switches that matter
delimiter- what separates tags in the incoming text. The default,treats comma-separated tags correctly. Leave it empty and every word is its own tag, which is rarely what you want.dedupe/ignore_case/ignore_emphasis- the deduping trio.ignore_caseon meansNeon Glowandneon gloware one tag;ignore_emphasison means(neon glow:1.4)andneon gloware one. The tooltip's suggested combo - emphasis ignored,keepset tolast- keeps the weighted spelling when a duplicate exists, so your(tag:1.4)survives the cleanup.keep-firstorlast: which spelling of a duplicate survives.remove_empty- drops tags holding nothing. This is what clears the run of bare commas an unconnected input leaves behind.collapse_whitespace- runs of spaces, tabs and line breaks inside a tag become one space. This is what removes the accidental line breaks from a pasted multi-line prompt.sort-nonekeeps written order (which preserves word order, the thing models actually read), or sort alphabetically/frequency if that's your workflow.limit- keep at most this many tags, counted after everything else runs. 0 keeps all. Useful for trimming a prompt to fit a token budget.
Outputs
text is the tidied prompt, joined back up with join_with (the default , is ordinary prompt spelling; \n gets one tag per line). tags is the surviving set as one LIST for the list nodes, tag_strings is the same tags as a STRING list - a node reading it runs once per tag, which is how you'd render once per tag if that's the experiment. count and removed report what survived and what went, and removed of 0 means your prompt was already clean.
The honest limits
Deduping is exact-match based, not semantic - it won't notice cat and feline overlap, and nothing should expect it to. Sorting by anything other than none reorders your tags, and for tag-driven models word position matters, so only sort when you mean it. The node also operates on the string level: it doesn't know or care which checkpoint you're prompting, so the quality-tag ordering advice from your model's docs is still your job.
Installing
Ships in WAS Node Suite v3 - ComfyUI Manager (search WAS Node Suite v3) or:
cd ComfyUI/custom_nodes
git clone https://github.com/WASasquatch/was-node-suite-comfyui
Restart after cloning; needs ComfyUI 0.14.0+ and Python 3.10+. Like every node in the v3 pack it installs nothing extra - no pip packages, no downloaded weights - which is a deliberate change from the old v2 suite's heavy dependency load.
Natural neighbors: put it after Prompt Parse when wildcard draws produce multi-tag lines you want deduped, and before a CLIP Text Encode when you want a clean, deterministic prompt string you can also save.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | The prompt to tidy, as `a tabby cat,, a tabby cat`. Typed here, or wired in from whatever built it: Text Concatenate, a style selector, or a caption node. | |
| delimiter | STRING | , | What separates one tag from the next in the incoming text. Leave it empty to treat every word as its own tag. Type \n to split a prompt written one tag to a line. |
| join_with | STRING | , | What is put between the tags on the way out. The default ', ' is the ordinary prompt spelling; type \n to get one tag per line, which is easier to read in a saved text file. |
| dedupe | BOOLEAN | true | Whether a tag appearing more than once is reduced to one. The survivor keeps the position of the first occurrence, so tidying does not reshuffle the prompt. |
| ignore_case | BOOLEAN | true | Whether 'Neon Glow' and 'neon glow' count as the same tag. Off, both survive, which is only useful where a downstream tool treats capitalisation as meaningful. |
| ignore_emphasis | BOOLEAN | true | Whether '(neon glow:1.4)' counts as the same tag as 'neon glow'. On with keep set to 'last' is the combination that collapses a prompt onto its weighted spellings, which is normally the intended one, the plain duplicate is usually what a second source contributed. |
| keep | COMBO | Which of a set of duplicates survives. `first` keeps the earliest spelling, `last` the latest. Position is the first occurrence either way, so keeping the last spelling does not move the tag to the end of the prompt. | |
| remove_empty | BOOLEAN | true | Whether tags holding nothing are dropped. This is what clears the run of bare commas an unconnected input leaves behind, which otherwise reaches the text encoder as it stands. |
| collapse_whitespace | BOOLEAN | true | Whether runs of spaces, tabs and line breaks inside a tag become a single space. This is what removes the line breaks a multi-line prompt box leaves in the middle of a tag. |
| sort | COMBO | How the surviving tags are ordered. `none` keeps the order they were written in, which is what preserves the weight early tags carry in most encoders. The alphabetical orders make two prompts comparable by eye; `longest first` puts the descriptive phrases ahead of the single words. | |
| limit | INT | 00–9999 | Keep at most this many tags, counted after everything else has run. 0 keeps all of them. Useful for trimming a caption model's output to the few tags worth keeping. |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| text | STRING | The tidied prompt, joined back up with join_with. |
| tags | ARRAY | The surviving tags as one LIST, for Text List Get and the other list nodes. |
| tag_strings | STRING | The same tags as a STRING list, so a node reading this runs once per tag, one render per tag, for instance. A prompt that tidies down to no tags leaves nothing to run on, so the nodes reading this socket stop and say so; the text output is still delivered, since an empty prompt is a valid one. |
| count | INT | How many tags survived. |
| removed | INT | How many entries the tidy-up took out, counting duplicates, empties and anything past the limit. 0 means the prompt was already clean. |