Build note

The characters you cannot see

There is a complete invisible alphabet in Unicode. Someone can write a sentence in it, paste it into the middle of a paragraph you are reading, and you will never know — unless something looks. This is the tool that looks.

I built this after reading through guillaumemeyer/watermarks-remover, a Python project that does something I had not seen anyone else do: it separates the parts of watermark removal it can prove from the parts it cannot, and tells you which is which. That honesty is the actual feature. The rest of this is a browser port of it.

What is actually hiding in text

Unicode has around 150 codepoints that render as absolutely nothing. Zero-width spaces. Word joiners. Two hundred and fifty-six variation selectors. An entire block of "tag characters" at U+E0000 that mirrors ASCII — meaning any message at all can be written in characters with no visible form, and carried inside an ordinary-looking sentence.

Here is a line of text. It looks like one sentence. It is carrying four separate marks:

The quarterly repоrt∅ ×14 is attached.∅ ×2 Please review before Friday∅ ×2.
Hidden message · Unicode tag characters
doc-id:7741-BX
Hidden message · variation-selector bytes
MB
The red blocks are where the tool made invisible characters visible. The Cyrillic о in "report" is a homoglyph — a different letter that looks identical. The tag characters spell out a document identifier. The variation selectors spell out initials. All of it survives copy-paste, and none of it survives this page.

The decoding is the part I care about most. Plenty of tools will strip invisible characters. Very few will tell you what was written in them, and that is the difference between "your text has been cleaned" and "someone tagged this paragraph with a document ID before sending it to you."

Three layers, two of which belong in a browser

The upstream project splits the problem in a way that survives contact with reality:

LayerWhat it isIn the browser?
A — deterministic Invisible Unicode, tag characters, variation selectors, bidi controls, homoglyphs, exotic spaces. A character is present or it is not. yes
B — statistical Watermarks built into which words a model picked. Removing one means rewriting the passage. no
File cleaners EXIF, XMP, IPTC, C2PA content credentials, PNG text chunks, PDF properties, Office and EPUB properties. yes

Layer B is missing on purpose, and the tool says so on its own front page. A statistical watermark is a property of word choice across a whole passage — the only way to remove it is to rewrite a substantial fraction of the text, sentence by sentence, which costs you your voice and requires a language model. In a browser that means either a multi-gigabyte download or an API call. The API call would break the one promise the tool makes, which is that nothing you paste in ever leaves your device. So it does the two layers it can do honestly, and is explicit about the third rather than implying coverage it does not have.

Two decisions I would defend

Images get surgery, not a re-encode

The common way to strip metadata from an image in a browser is to draw it onto a canvas and export it again. It works, and it is quietly destructive: your image is recompressed, transparency can be flattened, the colour profile is gone, and the file you get back has nothing in common byte-wise with the file you put in.

This tool parses the container instead. A PNG is a sequence of length-tagged chunks; a JPEG is a sequence of marker segments; a WebP is a RIFF. It drops the ones carrying metadata — including the PNG text chunk where image generators write your entire prompt back into the file — and copies every remaining byte through untouched. The pixels come out bit-identical. I test this by injecting an EXIF block and a trailing tracker string into a real photograph, running it through, and asserting the result is byte-for-byte the original file again.

PDF edits never change the file's length

A PDF ends with a cross-reference table recording the byte offset of every object in the document. Delete four bytes near the front and every offset after it is wrong — which is why so many "remove PDF metadata" scripts produce files that a reader refuses to open.

So nothing here deletes. Every edit overwrites in place with the same number of bytes: string contents become spaces, hex digits become zeroes, XMP packet bodies become whitespace. The xref stays valid and the document still opens. Running it over my own CV — a 279 KB PDF exported from a browser — it found the document title, the creation and modification timestamps, and, in the /Creator field, the full user-agent string of the headless Chrome that generated it, build number included. All 607 cross-reference entries still resolve afterwards.

That user-agent leak is a good illustration of why metadata is worth taking seriously. Nobody chose to put their browser build number in their CV. The export tool did it, silently, and it travels with every copy of the file.

The part most tools leave out

A watermark remover that reports success on everything is lying, so here is the list of things this one cannot do — the same list is on the tool's own page, one tab away from the button:

Findings are classified rather than just listed: confirmed (it was there, it is gone, check it yourself), probable, informational, and likely false positive — things it found, understood, and deliberately kept. A zero-width joiner inside a family emoji is structural, not a mark. So is an ideographic space in Japanese text, and a Cyrillic letter inside a Russian word. Getting those cases right is most of the work; a tool that strips every invisible character it sees will break emoji and mangle every language that is not English.

Checking my work

There is a test page that runs thirty assertions in your browser against the same modules the tool uses — the emoji case, the Russian case, the CJK case, PNG and JPEG and WebP and GIF round-trips, PDF length preservation, DOCX rebuild. The same file runs headlessly with node tests.node.js. If the tool's claims and the tests disagree, the tests are the ones I trust.

And you should not trust either of them over a real checker. exiftool -a -G1 will list everything still in an image, c2patool checks for content credentials, and qpdf --qdf --object-streams=disable makes a PDF greppable. If one of those disagrees with the report, the checker is right.

What it is for

Content you own or are authorised to process. Taking the GPS coordinates out of a photograph before you post it. Taking your name and your company off a document before it circulates. Finding out whether the text someone sent you has a tracking string sewn into it. Passing off machine-written work as your own or defeating attribution you agreed to is not what it is for, and removing a marker does not change what the content is.

No dependencies, no build step, no server, no account. Four small JavaScript modules and a page. It works offline after the first load, which felt like the right closing argument for a tool whose entire premise is that your files stay yours.

Have a look inside your own files

Paste a paragraph, or drop a photo. Nothing is uploaded — check your network tab.