NSFW Check (HF, Shared Model)
The gate that actually looks — and hard-stops the run if it's NSFW
- nsfw_model
- image
- block_policy
- image
NSFW Check (HF, Shared Model) is the node that does the actual work in this pack - everything else either feeds it a model or feeds it a policy. Drop it after a NSFW Load Model node, wire in an image, and it classifies that image and either lets it through unchanged or kills the run. It's built for the "check more than once" case: one instance after the input image, before you do anything expensive to it, and another right before Save Image, both pointed at the same loaded model. That gets you input- and output-side moderation for the cost of loading the classifier a single time.
Why does a hosted ComfyUI pipeline need this at all? Poke around r/comfyui and the honest answer from most solo users is closer to "I want to turn the filter off," not "I want another one" - a filter mostly exists to be disabled when you're the only person who'll ever see the output. That calculus flips the moment other people can hit your workflow: a public generator, a bot, an API that takes arbitrary prompts. There, an automated content gate isn't a nice-to-have, it's closer to table stakes - the payment processors and app stores that platforms depend on have gotten aggressive about what they'll let through, and "we didn't look at every image" isn't a defense that holds up. That's the gap this node fills, and it's a genuinely thin corner of the ComfyUI node ecosystem otherwise.
How it works
Feed it a loaded nsfw_model and an image, and it runs the classifier, gets back one of five labels - porn, hentai, sexy, drawing, or neutral - and checks that label against whatever block_policy you wired in (or the pack's default if you didn't: porn/hentai/sexy blocked, drawing/neutral allowed). If the label clears the policy, the image passes through the output unchanged. If it doesn't, the node doesn't blur or swap anything - it fires an internal nsfw_guard.content_blocked event, calls interrupt_processing(True), and raises an error typed nsfw_content_detected. Your run stops, full stop. That's a meaningfully different design from filters that quietly hand back a censored image; you need to actually handle the error path here, not just check whether the output "looks blurred."
The inputs and outputs that matter
nsfw_model(NSFW_GUARD_MODEL) - required, comes from aNSFW Load Modelnode upstream. This is what makes it the "shared model" variant instead of loading its own copy.image(IMAGE) - required, the thing being screened.block_policy(NSFW_BLOCK_POLICY, optional) - plug in aNSFW Filter Policy (Level 1-4)orNSFW Filter Policy (Label Table)node here if you want a different policy at this specific checkpoint than the model's built-in one. Leave it unconnected to use the default.
One output: image. When nothing's blocked it's the identical image you fed in - wire it straight into whatever comes next, a save node, another processing step, or a second check further down the graph.
How to install it
Whole pack, one install. ComfyUI Manager: search "NSFW Guard", install, restart. Or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/vuhung3990/comfyui-nsfw-guard
pip install -r comfyui-nsfw-guard/requirements.txt
restart ComfyUI, and you'll have all five nodes in the pack, this one included. You'll need a NSFW Load Model node somewhere in the same graph - this node has no model_repo of its own to fall back on.
Common issues & troubleshooting
"NSFW_GUARD_MODEL input has no valid connection." You skipped the loader. This node is deliberately dumb about model loading - it only accepts a model that's already been loaded elsewhere.
Run dies mid-workflow with nsfw_content_detected and you didn't expect it. That's the node doing its job, not a bug. If you're getting more false positives than you'd like, that's a policy problem, not a model problem - loosen it via a block_policy input (drop sexy off the block list, for instance) rather than assuming the classifier is broken.
Wondering why it's slower than the single all-in-one node. It shouldn't be, if you're actually reusing the loaded model - that's the entire point of the two-node split. If it feels slow, check you're not accidentally running a separate NSFW Load Model per check instead of sharing one across all of them.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| nsfw_model | NSFW_GUARD_MODEL | — | |
| image | IMAGE | — | |
| block_policyopt | NSFW_BLOCK_POLICY | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |