Skip to main content
AI Watermark Removal

AI Watermark Lab · Study 02

Which invisible characters survive ordinary software

We ran 18 invisible characters through 12 transformations that real pipelines apply to text. The genuinely invisible characters survive almost everything. The ones that get cleaned up are the ones that at least look like a space. That is backwards from how most people assume text hygiene works, and it explains why these characters accumulate.

Published 2026-08-12Updated 2026-08-12Research/proposal

The finding in one line

Twelve of the eighteen characters came through every transformation that was not deliberately trying to remove them. That includes JSON, URLs, base64, line trimming, and canonical Unicode normalization. Nothing incidental touches them.

How many of 18 characters survive each transformation

Characters surviving, out of 18

How many of 18 characters survive each transformationHow many of 18 characters survive each transformation. NFC / NFD / JSON: 18 Characters surviving, out of 18. NFKC / NFKD: 14 Characters surviving, out of 18. Whitespace collapse: 12 Characters surviving, out of 18. Strip \p{Cf}: 7 Characters surviving, out of 18. Latin-1 storage: 2 Characters surviving, out of 18. Strip non-ASCII: 0 Characters surviving, out of 18.NFC / NFD / JSON18also URI, base64, per-line trimNFKC / NFKD14destroys 4 space-like charactersWhitespace collapse12destroys 6, including the BOMStrip \p{Cf}7targeted, and still misses 7Latin-1 storage2lossy, and destroys real text tooStrip non-ASCII0also destroys every non-Latin script018

Only the last three do anything decisive, and all three are destructive to ordinary text as well. The top two rows are the transformations text actually passes through in normal use, and they remove nothing.

Source:
Original measurement, AI Watermark Lab
Sample:
18 characters × 12 transformations = 216 tests
Method:
Each character is embedded in a two-line carrier string, the transformation is applied, and the exact code point is checked for afterwards. One character per test, so there are no interaction effects.
Date:
2026-08-12
Limitations:
Only transformations that can be executed and verified in code. It says nothing about Google Docs, Word, Notion, or any application this script cannot run. That is precisely why those are not claimed.

Why the invisible ones survive and the space-like ones don't

Every transformation that removed anything did so for the same underlying reason: it recognised the character as a kind of space. NFKC maps no-break space, thin space, and ideographic space onto an ordinary space, because for compatibility purposes they are one. JavaScript's \s matches the same set plus the byte-order mark. That is why the BOM is the one truly invisible character that a whitespace collapse destroys.

A zero-width space is not a space to any of these rules. It has no width, no compatibility decomposition to anything, and it is not whitespace. So it passes through untouched, and so do the joiners, the bidirectional controls, the soft hyphen, the variation selector, and the tag character.

The practical consequence is the opposite of the intuition. Text that has been through several systems is more likely to carry zero-width characters and less likely to carry unusual spaces, because the ordinary cleanup steps quietly remove one class and never see the other. Finding a zero-width space in a document tells you almost nothing about where it came from. In any case, our census of 96 Claude outputs found none at all, so it did not come from there.

Every transformation, and what it destroyed

Survivors / destroyed, out of 18 characters. 2026-08-12.
TransformationSurvive / destroyedWhere you meet it
Unicode NFC normalization18 / 0Default for storage and comparison in many systems
Unicode NFD normalization18 / 0Canonical decomposition; used by some filesystems
JSON round-trip18 / 0Every API call, config file, and log line
URI encode and decode18 / 0Query strings, forms, anything travelling in a URL
Base64 round-trip (UTF-8)18 / 0Email transport, data URIs, token payloads
Per-line trim18 / 0Editors on save, most Markdown pipelines
Unicode NFKC normalization14 / 4Compatibility normalization; identifier rules, search indexes
Unicode NFKD normalization14 / 4The aggressive cousin of NFKC
Whitespace collapse (/\s+/)12 / 6The most common 'tidy this up' regex in production
Strip Unicode format chars (\p{Cf})7 / 11The targeted removal, which leaves real text alone
Latin-1 storage (lossy)2 / 16A legacy column that keeps only each character's low byte
Strip non-ASCII0 / 18The naive sanitizer; also destroys every non-Latin script

Every character, and how much it survives

Sorted by durability. The split down the last column is the whole result: no space-like character reaches the top of the table, and no truly invisible character reaches the bottom except the byte-order mark, which JavaScript treats as whitespace.

Transformations survived, out of 12. 2026-08-12.
CharacterSurvivesClass
U+00AD soft hyphen10Truly invisible
U+034F combining grapheme joiner10Truly invisible
U+FE0F variation selector 1610Truly invisible
U+200B zero width space9Truly invisible
U+200C zero width non-joiner9Truly invisible
U+200D zero width joiner9Truly invisible
U+2060 word joiner9Truly invisible
U+061C Arabic letter mark9Truly invisible
U+200E left-to-right mark9Truly invisible
U+202D left-to-right override9Truly invisible
U+2066 left-to-right isolate9Truly invisible
U+E0041 tag character9Truly invisible
U+1680 Ogham space mark9Space-like
U+FEFF byte-order mark8Truly invisible
U+00A0 no-break space8Space-like
U+202F narrow no-break space7Space-like
U+2009 thin space7Space-like
U+3000 ideographic space7Space-like

Where this study stops

  1. Only transformations that run in code. The question people actually ask, does a mark survive Google Docs, Word, or Notion? That cannot be answered here, so it is not answered here.
  2. Survival means the exact code point is still present. It does not mean the surrounding text is unchanged: NFKC and a whitespace collapse both alter plenty besides.
  3. One character per test. Real text carries combinations, and some transformations behave differently on a sequence than on a single character.
  4. This says nothing about statistical text watermarking, which lives in token choice rather than in characters and cannot be observed by any of these methods.

Data and code

Reuse is welcome with attribution and a link back. If you add a transformation we should have included, that is worth telling us. See the corrections policy.

Related