Identify and remove AI watermarks and provenance metadata from your own images and video.
Model Context Protocol (MCP) Server: io.github.wiltodelta/remove-ai-watermarks
This MCP server provides functionality to identify and remove AI watermarks and provenance metadata from your own images and video. Its purpose is focused on watermark/provenance removal, with inputs targeted specifically at user-owned media.
🛠️ Key Features
Identify AI watermarks
Remove AI watermarks
Remove provenance metadata
Operate on images and video
Target your own images and video
🚀 Use Cases
Cleaning AI-marked images before sharing
Removing provenance metadata from video assets
Preparing personal media by stripping watermarking artifacts
Post-processing user-owned media for reduced metadata traces
⚡ Developer Benefits
Clear scope: watermark and provenance metadata removal
Media-type coverage: images and video
Developer-facing intent grounded in identifying and removing specific metadata/artifacts
⚠️ Limitations
Described as applicable to your own images and video (not third-party media)
Remove AI provenance marks from images and video you generated yourself:
known visible labels such as the Google Gemini sparkle watermark and vendor text marks;
invisible pixel watermarks through direct local-format disruption or diffusion regeneration;
C2PA, EXIF, XMP, IPTC, and related AI metadata.
Before
After
Image with a visible Gemini watermark
Image after visible watermark removal
bash
uv tool install "remove-ai-watermarks[visible]"# CLI for visible marks and metadata
npx skills add wiltodelta/remove-ai-watermarks # agent skill for Claude Code, Codex, Cursor, and other agents
Video support covers provenance identification, complete visible-plus-metadata
cleaning, directory batches, visible Sora, Veo, Seedance, Doubao, Dola,
Hailuo AI, and Kling AI mark removal, and oracle-certified VAE regeneration for video SynthID
removal.
raiw.cc runs this library as a hosted service, with the GPU
included and nothing to install. Visible mark and metadata removal at Standard
output up to 12 MP are free there; original resolution above 12 MP and invisible
watermark removal are paid.
This is a research project on AI provenance signals, for lawful use on content
you own. It is provided as is, without warranty or liability, and each user is
responsible for how they use it. It does not target stock agency previews or
other watermarks that protect third party paid content. Some jurisdictions,
including China, restrict removing AI labels or supplying tools that do. See
scope, safety, and legal notes.
Choose what you want to do
Goal
Command
GPU
Find provenance signals and watermarks
identify
No
Classify a photograph from pixels (opt-in, not provenance)
classify
No
Remove known visible AI marks
visible
No
Erase a region you select
erase
No
Strip AI metadata
metadata
No
Identify supported video provenance
video identify
No
Remove visible marks and AI metadata from video
video all
No
Strip AI metadata from video
video metadata
No
Remove a registered visible AI mark from video
video visible
No
Process a directory of videos
video batch
Depends on mode
Apply the calibrated video-pixel SynthID-removal profile
video invisible
Recommended
Regenerate an image to disrupt invisible watermarks
invisible
Required (CUDA)
Run visible, invisible, and metadata removal
all
Recommended
Process a directory
batch
Depends on mode
Microsoft Paint and Photos InvisMark declarations are routed automatically to
pixel regeneration. The all command removes both the hidden pixel watermark and
its linked C2PA manifest; metadata stripping alone removes only the manifest. A
specialized Python API can inspect and disrupt the validated local
Watermarker.dll payload without diffusion.
Every production feature available on the active Python
remove-ai-watermarks[all]
Lower-level and specialized extras include pixels, heif, trustmark,
migan, lama, diffusion, classify-onnx, and source-classify. The
installation guide documents their exact
dependency composition, Python compatibility, and model requirements.
Quick start
Install the metadata-focused default CLI:
bash
uv tool install remove-ai-watermarks
Inspect an image:
bash
remove-ai-watermarks identify image.png
To classify a photograph from pixels (AI versus camera, optional provider),
install the extra and call classify. identify never starts it:
For a lightweight, abstaining OpenAI/Google/unknown source-export signal after
metadata removal, use the separate Python API. It is not a SynthID detector:
python
import remove_ai_watermarks as raiw
result = raiw.classify_source("image.png")
print(result.label, result.reason)
Signed provenance is the supported route for SynthID and identify reads it.
There is no local SynthID pixel detector in the package. Research on a
periodic lattice expert is in scripts/synthid_runtime/ and
synthid-detector-research.md.
For visible watermark removal, install the pixel dependencies:
Without -o this command overwrites the source in place.
Inspect or remove AI metadata from an MP4, MOV, M4V, WebM, MKV, AVI, or FLV
file:
bash
remove-ai-watermarks video metadata input.mp4 --check
remove-ai-watermarks video metadata input.mp4 --remove -o clean.mp4
The video metadata command does not transcode video or audio streams. Unlike
the image command above, when -o is omitted it writes <source>_clean and
preserves the original. MP4 and MOV
inspection includes the native TC260 AIGC tag in
moov.udta.meta.keys/ilst, including a moov placed after the media payload,
plus the QuickTime-form meta variants Doubao's iOS export writes (a bare
meta box as a direct moov child, and a keyless hdlr=mdir metadata list).
Keyed workflow and prompt entries in the same metadata-list structure are
also detected and removed, including ComfyUI exports.
MKV and WebM inspection reads the normative
Segment.Tags.Tag.SimpleTag placement. AVI uses LIST/INFO/AIGC, while FLV
uses script.onMetaData.AIGC. The non-ISOBMFF formats are remuxed with stream
copy for removal.
Use the product-oriented video path to identify or clean a file:
bash
uv tool install --force "remove-ai-watermarks[video]"
remove-ai-watermarks video identify input.mp4
remove-ai-watermarks video all input.mp4 -o clean.mp4
video all removes a stable registered visible mark when present and always
strips verified AI metadata. If neither signal is found, it still writes a
same-container passthrough, so application callers get one predictable output
contract. Proprietary invisible-video removal is excluded by default.
--invisible opts into the lossy, oracle-certified video SynthID profile.
Process a directory with the same contract:
bash
remove-ai-watermarks video batch ./videos --mode all
Remove a supported visible video mark:
bash
remove-ai-watermarks video visible input.mp4 -o clean.mp4
remove-ai-watermarks video visible veo.mp4 --mark veo -o veo_clean.mp4
remove-ai-watermarks video visible seedance.mp4 --mark seedance -o seedance_clean.mp4
remove-ai-watermarks video visible dola.mp4 --mark dola -o dola_clean.mp4
remove-ai-watermarks video visible hailuo.mp4 --mark hailuo -o hailuo_clean.mp4
remove-ai-watermarks video visible kling.mp4 --mark kling -o kling_clean.mp4
This path scans the complete sequence before changing pixels. It accepts only a
mark that repeats at a stable position across adjacent frames, then reuses the
same OpenCV, MI-GAN, or LaMa fill backends as image removal. Audio is copied
without re-encoding and is allowed to reach its natural end; the video stream
is transcoded because its pixels change. By default, a guarded optical-flow
pass motion-aligns the preceding accepted fill and blends it only when the
nearby source context agrees; use --no-temporal-consistency to disable it.
The encoder preserves supported
8-bit source chroma sampling, color tags, and MP4/MOV track timescale instead
of relying on ffmpeg's implicit raw-BGR defaults. Variable frame intervals are
preserved through a timestamped in-memory NUT bridge instead of being flattened
to the average frame rate. Non-zero source start timestamps are retained
together with the copied audio offset. The default --mark auto
scans all providers in one decode pass and selects the first stable match in
the specificity order shown below. Valid Google AI-video provenance breaks a
Sora/Veo cross-match in favor of Veo when the diamond is nested in the Sora
region or Veo persists through the complete clip while Sora does not.
Pass an explicit mark to restrict detection to one provider.
Sora covers the moving Sora 2 mascot, with or without the wordmark; mascot-only
matches also require the complete two-eye shape. Veo covers both the current
four-point diamond and the legacy Veo text. Seedance covers the fixed boxed
AI label, Dola covers the fixed Dola AI text, Hailuo AI covers the composite
MINIMAX | hailuo AI label, and Kling AI covers the bottom-right KLING AI or
KlingAI label with its version suffix. A completed encode is published
atomically. No output is written when no stable mark is found.
HDR, PQ/HLG, and greater-than-8-bit inputs are rejected before encoding rather
than silently reduced through OpenCV's 8-bit BGR boundary.
Apply the calibrated video-pixel SynthID-removal profile:
This path regenerates the complete sequence with one latent-noise field shared
across time, copies complete audio, strips source metadata, and publishes the
completed encode atomically. The default noise_std=0.15 profile passed both
the two-carrier calibration and a complete public eight-second Veo oracle
check. Google does not publish a local decoder, so a fresh provider check
remains useful for unusually important files or after provider changes, but it
is not a product result state. The CLI therefore describes video-pixel
regeneration instead of claiming a per-file SynthID verdict, and reports the
copied audio watermark as UNVERIFIED.
For invisible watermark removal through the CLI or high-level API, install the
qwen-zimage extra. An NVIDIA GPU is required: all diffusion profiles are
CUDA-only, and there is no CPU or MPS fallback. The specialized local Paint API
uses the pixels extra without CUDA.
Typography-heavy images can opt into the experimental verified-text post-pass.
It accepts manually reviewed strings and line boxes or an operator-verified
geometry-only manifest; it never treats raw OCR output as ground truth or runs
automatically:
See the CLI guide for the manifest
schema, compatibility restrictions, and oracle caveats.
See the installation guide for Homebrew, uv, optional
features, and development setup.
Examples
Visible Gemini mark
The after raster at the top of this page is generated from the tracked before
raster by the public path:
bash
uv run remove-ai-watermarks visible demo_banana_before.png \
--backend cv2 -o demo_banana_after.png
High quality invisible removal
qwen-zimage is the default profile: a Qwen-Image-2512 Lightning pass under Canny
ControlNet, followed by SAM-masked Z-Image repair of any detected face. The
alternative, sdxl-zimage, swaps the global stage for SDXL and keeps the same face
stage. A third profile, chroma-zimage, uses the Apache-2.0 Chroma1 global pass
with its own flat vendor floors; see docs/chroma1-engine-research.md for the
calibration. --pipeline auto picks sdxl-zimage for Google, chroma-zimage for
Microsoft, and qwen-zimage otherwise. All are CUDA only.
These exact output files were checked with the matching provider verifiers. That
result applies to these files, not to every seed, image, or future watermark
version.
The default --mark auto checks all registered visible marks and removes every
match. If the mark is visible to you but the detector misses it, select its
region explicitly:
--region uses x,y,width,height and may be repeated.
Use a learned fill backend
The visible extra uses OpenCV inpainting when no learned backend is installed.
For more difficult backgrounds, the learned-backend extras include the same
pixel dependencies automatically:
CPU offload lowers CUDA memory pressure by moving model components between CPU
and GPU, at the cost of speed.
Process a directory
bash
remove-ai-watermarks batch ./images --mode visible
remove-ai-watermarks batch ./images --mode all
What the tool can recognize
Visible mark support includes:
Google Gemini and Nano Banana visible sparkle watermark;
Doubao, the Jimeng wordmark and top-left AI生成 layouts, Qwen, Kling AI,
Yuanbao, Dola, WorkBuddy, Baidu, LiblibAI's bottom-center wordmark and compact
top-left pill, and RunningHub labels;
calibrated Microsoft top-right white and beige AI-badge layouts;
calibrated Italian and Korean Samsung Galaxy AI disclosures;
a generic brand-less bottom-right AI生成 fallback for OS/gallery-level
AI-edit stamps that carry no vendor wordmark of their own (vivo and Xiaomi
Gallery confirmed); synthetic-only calibration, weaker evidence than the
vendor-tuned detectors above;
the OpenArt wordmark, placed at the frame center rather than a corner;
uncalibrated (one confirmed real case, no captured corpus).
Metadata and provenance inspection covers C2PA, EXIF, XMP, IPTC, common
generator parameters in image and video containers, China TC260 AIGC labels,
and several vendor specific signals. Optional decoders add support for open
DWT-DCT watermarks and Adobe TrustMark.
The exact support matrix, including important locale and detector limits, lives
in supported signals. The
synthetic example gallery carries one canonical
sample for every registered image and video mark.
How it works
Visible removal follows three steps:
Detect a registered mark in its expected area.
Build a mask around the mark.
Fill only the masked region with OpenCV, MI-GAN, or LaMa.
Metadata removal uses format aware stripping. JPEG metadata removal preserves
the encoded image scan instead of recompressing it. Native MP4/MOV TC260 values
and keyed generation parameters are blanked without changing box sizes or
media offsets. Other supported containers use their corresponding metadata
path.
Invisible removal through the CLI and high-level API regenerates the image through
a diffusion pipeline. Specialized callers can instead decode and disrupt the
positively identified local Microsoft Paint format with much smaller pixel changes.
Neither path can guarantee that every proprietary verifier will reject every output.
The high level API accepts a file path or a BGR NumPy array. For path inputs it
also reads provenance metadata, preserves alpha, and can strip AI metadata from
the written result.
See the Python API guide for visible removal, the full
remove_all and remove_batch pipeline, provenance inspection, metadata
stripping, and diffusion usage.
Agent skill
Coding agents can install the published skill and drive this CLI:
bash
npx skills add wiltodelta/remove-ai-watermarks
Claude Code can add this repository as a plugin marketplace:
The separate
ComfyUI Remove AI Watermarks
package provides nodes for visible removal, detection, region erasing, and
invisible removal.
Important limitations
A missing local signal means unknown, not clean. Proprietary pixel
watermarks may remain after metadata has been stripped.
What each path leaves behind
lists, per command, what may remain and how to check it.
Visible removal reconstructs a small region. Results depend on the background
and selected fill backend.
Invisible removal changes the whole image and may alter faces, text, or fine
detail.
Visible video removal recognizes the moving Sora 2 wordmark, the current Veo
diamond plus legacy Veo text, the Seedance boxed AI label, and the fixed
Doubao, Dola, Hailuo AI, Vidu, and Kling AI labels. It does not recognize the older Sora Turbo
corner swirl or unregistered layouts from those providers.
The classical OpenCV backend can smear structured backgrounds; use MI-GAN or
LaMa when recovery quality matters.
Video SynthID regeneration changes resolution, frame rate, and image detail.
The shipped profile is oracle-certified, but no public local decoder can
certify an arbitrary output at runtime. Recheck unusually important outputs
after provider changes.
Invisible-watermark removal through the CLI and high-level API requires CUDA.
All diffusion profiles refuse any other device at construction rather than
falling back to one that cannot run them. The specialized local Paint API,
visible removal, metadata stripping and identify run without CUDA.
Provider watermark systems can change. Validate important outputs with the
provider's own verifier when one is available.
The shipped video invisible command uses the certified noise_std=0.15
profile. The companion scripts/video_synthid_sweep.py research harness builds
a matched re-encode control plus VAE-regenerated candidates and leaves the
verifier verdict blank:
bash
uv run --extra video --extra diffusion python scripts/video_synthid_sweep.py input.mp4 -o sweep/
To score what an output actually cost, use scripts/video_fidelity_probe.py:
the engine's own PSNR is measured after the input resize and before final
encoding, so only the probe sees the delivered picture.
bash
uv run --extra video python scripts/video_fidelity_probe.py input.mp4 input_clean.mp4
The control must still be SynthID-positive before a negative candidate can
count as removal evidence. In the 2026-07-29 two-clip calibration, both matched
controls were positive in Gemini's built-in SynthID verifier; the stronger
candidate was negative on both carriers, while a weaker candidate was
negative on one. A later adversarial follow-up that asked ordinary Gemini to
reinterpret the pixel result returned UNAVAILABLE; that follow-up was not a
verifier rerun and does not invalidate the built-in verdicts. A 2026-07-31
full-clip check on a public eight-second Veo sample found 0.10 still detected
and 0.15 not detected, so 0.15 is now the certified default. The
reproducible hashes and verdicts for that full-clip check -- one carrier, two
rows -- live in data/evaluations/video-synthid-oracle.csv. The earlier
two-clip calibration is narrative only: its verdicts were not recorded in a
tracked manifest, so treat the certified default as resting on the 2026-07-31
rows.
Research notes and historical experiments are listed separately in the
documentation index. They explain past decisions but do not
define the current public API.
Contributing
Install the development environment and run the project gate:
bash
uv sync --frozen --extra dev
bash maintain.sh
See module internals before changing a subsystem
with documented invariants. Report vulnerabilities as described in
SECURITY.md.