550W Remove Image Watermark
What 550W Remove Image Watermark really does
- result_json
The pitch, and the catch
You can already erase a watermark locally. Flux Fill inpainting does it, and instruction editors like Flux Kontext and Qwen-Image-Edit turned out to be weirdly good at it - the community has been using them as watermark erasers since 2025 without really planning to. So why install something called 550W Remove Image Watermark (class FiftyWImageUpload)?
Why? That local path costs you a masked region and a prompt per image, and sometimes a re-roll. This node is the other trade: it uploads your picture to a metered cloud service, and a JSON string comes back with a link to the cleaned result. You don't own the model or control the filter, and it costs credits per image. What you buy is consistency across a folder of files, with no inpainting fiddling.
One honest caveat the author puts in the README, and I'll repeat it: only run this on media you own or have permission to edit.
How it works
Despite the class name, nothing gets "uploaded" in the ComfyUI sense. The file widget is a dropdown built by walking ComfyUI/input for .png, .jpg, .jpeg and .webp - same directory your LoadImage uploads land in. On run, the path is resolved through folder_paths.get_annotated_filepath() and checked that it's still inside the input directory, which is a sane traversal guard.
Then it's one multipart POST to the service's image endpoint with your credentials, a stable operation id, and a synchronous flag. The node blocks while the service works - you'll see the queue sit there - capped at 50 MiB per image and a 60-second read timeout. What comes back is the raw service JSON, dumped into result_json with non-ASCII preserved.
That string is the point of the node, and it's also the thing beginners get wrong: result_json is a STRING, not an image. Wire it into 550W Image Result (FiftyWImageResult), which accepts the JSON, refuses anything that isn't a finished task, downloads the resultUrl - host-locked to i.550wai.cn, redirects rejected - and emits a native IMAGE. Then Preview Image or Save Image as usual. Skip that step and you're staring at JSON wondering where your picture went.
The four widgets that matter
file- pick from what's inComfyUI/input; the node's upload button drops files there.operation_id- a stable id, 8 to 64 characters of[A-Za-z0-9._:-]. The default is empty and empty fails validation, so type something likebatch-2026-10-05-aand keep it stable across reruns.confirm_charge- must beTrue. This is the author making you acknowledge the paid call; leaving it off raises "Invalid input" before any request goes out.auth_mode-api_key(default) oroauth. Andlanguage(zh-CN/en) only changes which language the errors come back in.
Install
ComfyUI Manager is the easy route: search the pack title, install, restart. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/sunshinehu/comfyui-550w-media-cn
# then, with ComfyUI's own python:
python -m pip install -r comfyui-550w-media-cn/requirements.txt
That pulls exactly three things - requests, requests-toolbelt, keyring. No torch, no models, nothing GPU-shaped. Python 3.11+.
For the default api_key mode, grab a key and user number from the provider's key page and export them before starting ComfyUI:
export FIFTYW_API_KEY="..." # from https://qzm.550wai.cn/api-keys
export FIFTYW_USER_NO="..."
OAuth is nicer if you hate keys, but it needs an OS credential store and a browser on the same machine:
cd ComfyUI/custom_nodes
python -m <installed-dir-name>.oauth_cli connect # e.g. comfyui-550w-media-cn
Where people get burned
"Invalid input" and nothing else. That message covers four different causes: no confirm_charge, a missing/too-short operation_id, a file over 50 MiB, or too many files in the graph. Check the id first - it's the least obvious.
Re-running after a network blip. The error for a lost request is literally "Request outcome unknown; query the task before retrying," and the pack never retries a paid task for you. Reusing the same operation_id on a rerun is the intended way to tie the second attempt back to the first; don't let it randomize.
OAuth silently refusing to work. keyring on a headless Linux box usually has no Secret Service backend, and this pack deliberately refuses plaintext fallback rather than quietly storing a token in a file. Remote or desktopless hosts should just use the API key.
Sharing the instance. This connection is account-level, not per-browser-user. If you OAuth an instance your friends can reach, they're spending your credits.
Nothing in the file dropdown. The list is built when the node loads its inputs, so a file dropped in after that may need a refresh or a re-added node.
Last thing: this pack has no community footprint at all, so the README and the source are your whole documentation - and the source is the more reliable half.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| language | COMBO | en | 2 options: zh-CN, en |
| file | COMBO | 1 options: example.png | |
| operation_id | STRING | — | |
| confirm_charge | BOOLEAN | false | — |
| auth_modeopt | COMBO | api_key | 2 options: api_key, oauth |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result_json | STRING | — |