How it works
The whole method, including the parts that make it slower and more careful than the alternatives. If you are going to trust a tool with your document, you should be able to read what it does to it.
There are two kinds of watermark
Almost every confused conversation about AI watermarking comes from mixing these two up, so it is worth separating them before anything else.
Edit-based watermarks are data added to a file: invisible Unicode characters in text, metadata blocks in images. They are discrete, findable, completely removable. If one is present, we find it; once removed it is gone, and you can verify that by re-running the check.
Statistical watermarks are patterns in the content itself. Google's SynthID for text biases which words the model samples; SynthID for images embeds a pattern across the pixels. There is no discrete thing to delete. Detecting them requires the key that was used to embed them, which is not public for any deployed system.
This tool handles the first category completely and reports honestly about the second. Any product claiming to detect or remove SynthID from text is either confused or lying, because the detection key is not available to them either.
Text: the carrier codepoints
Detection is deterministic, not statistical. A character is either in the carrier set or it is not. The set covers:
- Zero-width family.
U+200Bzero-width space,U+200Cnon-joiner,U+200Djoiner,U+2060word joiner,U+FEFFbyte-order mark,U+180EMongolian vowel separator. - Tag characters.
U+E0001andU+E0020–U+E007F. This block mirrors ASCII and renders as nothing, so it can carry a complete hidden message. - Variation selectors.
U+FE00–U+FE0FandU+E0100–U+E01EF. Free-floating, these encode arbitrary bytes. - Bidirectional controls.
U+202A–U+202Eplus the isolatesU+2066–U+2069andU+061C. - Private-use areas.
U+E000–U+F8FFand the two supplementary private planes. No standard meaning, so no innocent explanation. - Invisible operators and annotations.
U+2061–U+2064,U+FFF9–U+FFFB,U+00ADsoft hyphen,U+034Fcombining grapheme joiner. - Space homoglyphs. Sixteen characters that look like a space but are not
U+0020, includingU+00A0,U+202FandU+2009. These are normalised to a plain space rather than deleted.
Anything else in Unicode category Cf that is not accounted for above is also caught, so novel carriers do not slip through just because they are not on the list.
Why we keep some invisible characters
This is the part that separates a careful tool from a regular expression, and it is the reason this one is worth using.
A tool that deletes every invisible character works fine on English and silently corrupts everything else. Specifically:
U+200Cis orthography in Persian. میروم requires it; without it the word is wrong. The same holds for conjunct control in Devanagari and other Indic scripts.U+200Dbinds emoji sequences. Strip it from 👨👩👧 and you get three separate people.- Subdivision flags are built from tag characters, the same block used to smuggle text. 🏴 is a flag base plus the tag sequence for "gbsct" plus a terminator.
- Variation selectors after a CJK ideograph select a regional glyph variant and are meaningful.
- Mongolian free variation selectors, Khmer inherent vowels, Hangul jamo fillers: all invisible, all load-bearing.
- Right-to-left marks and correctly paired embeddings are normal in mixed-direction text.
So every candidate is judged in context rather than in isolation. A zero-width joiner between two emoji bases is kept; the same character between two Latin letters is removed. A tag character inside a complete, well-formed flag sequence is kept; the same character in a bare run is removed. A variation selector following a CJK ideograph is kept; a free-floating one is removed.
Everything found is reported either way. Preservation affects what gets deleted, not what gets shown to you, and every preservation rule can be overridden with an explicit option.
Two confidence levels
Findings are labelled probable or informational.
Probable means the character has no legitimate role in ordinary prose: zero-width characters, tag characters, private-use codepoints, free-floating variation selectors. Something put it there.
Informational means it has an innocent explanation that is more likely than a deliberate mark for it. That is mainly space homoglyphs, which web pages, PDFs, word processors produce constantly. We report them and clean them, and we do not pretend they prove anything.
Images: container-level removal
Metadata is removed by rebuilding the container, never by re-encoding the image. The compressed pixel data is copied through byte for byte, so a JPEG does not lose a generation of quality and the output pixels are bit-identical to the input.
PNG
We walk the chunk list and keep IHDR, PLTE, IDAT,IEND, the colour chunks (tRNS, gAMA, cHRM,sRGB, iCCP, sBIT) and the APNG animation chunks (acTL, fcTL, fdAT). We drop tEXt,zTXt, iTXt, eXIf, caBX (the C2PA container) and any non-standard private chunk. Because whole chunks are removed and none are modified, the surviving CRCs remain valid without recomputation. Bytes appended afterIEND, which is a common hiding place, are also dropped.
JPEG
We walk the segment list and drop APP1 (EXIF and XMP), APP11 (JUMBF, which is where C2PA lives), APP13 (IPTC) and COM. We keepAPP0 (JFIF), the ICC profile in APP2, and the AdobeAPP14 marker. That last one declares the colour transform, and dropping it can invert an image's colours. From the start-of-scan marker onward, everything is copied verbatim.
WebP
We keep VP8 , VP8L, VP8X, ALPH,ANIM, ANMF and ICCP, and drop EXIF,XMP and C2PA. The EXIF and XMP presence flags in theVP8X header are cleared so the file does not advertise chunks that are no longer there, and the RIFF size field is rewritten.
The writing-style score
Separate from watermark detection, and clearly labelled as a heuristic. It counts em-dash density per thousand words, a list of stock phrases, the coefficient of variation of sentence length, curly-quote frequency, bolded bullet lead-ins, three-item list frequency. Each contributes a weighted severity; short inputs are damped because they cannot support a confident read.
It is a measure of what a human grader would notice. It is not a probability that text is AI-generated, and it cannot read a statistical watermark. Every signal that contributed is listed so you can decide whether you agree with it.
What happens to your data
Text and images are processed in memory and discarded when the response is sent. Nothing is written to disk, nothing is logged, nothing is used for training.
The only thing stored is a salted SHA-256 hash of your IP address, truncated, used to count free checks against the daily allowance. It is not reversible in practice and rows older than a week are deleted.
Credit where it is due
The Unicode carrier set and the context-aware preservation rules are a TypeScript port of the approach inguillaumemeyer/watermarks-remover, which is the most careful treatment of this problem we have found, in particular its insistence on not corrupting non-Latin text, which most tools in this category get wrong. The image container work also draws onwiltodelta/remove-ai-watermarks.
Try it on your own document
Checking is free and needs no account. You only pay if you want the clean copy.
Check my text