Why a blank character survives where a space does not
Most apps tidy input by trimming whitespace, and Unicode properties define what counts as whitespace. An ordinary space, a no-break space (U+00A0) and an em space (U+2003) all have the White_Space property, so a trim removes them and a name made only of them is treated as empty. The zero-width space (U+200B) is a format character, the Hangul filler (U+3164) is classed as a letter and the braille blank (U+2800) as a symbol, so a plain trim leaves them alone.
That is the whole trick behind blank usernames and empty-looking messages. It works only until the platform decides otherwise: many services strip or reject these characters explicitly, and each one filters a different set. If one row is refused, try the next. Nothing on this page can force an app to accept a blank name.
What each character on the list is for
None of these characters was created for hiding things. The zero-width space marks a place where a long string may wrap, for example inside a long URL or between words in scripts written without spaces. The word joiner (U+2060) does the opposite and forbids a line break at that point. The no-break space keeps two words on one line, as in 10 km.
The zero-width non-joiner (U+200C) stops two letters from connecting in scripts such as Persian, where it is part of correct spelling. The zero-width joiner (U+200D) asks for the connected form and is also what glues several emoji into one, such as a family built from separate people. The Hangul filler is a placeholder from Korean character sets, and the braille blank is the braille cell with no raised dots.
Where hidden characters come from and what they break
Hidden characters arrive by copy and paste. Word processors and web pages insert soft hyphens (U+00AD) and zero-width spaces to control line wrapping, some editors save files with a byte order mark (U+FEFF) at the start, and messaging apps add direction marks around mixed left-to-right and right-to-left text. They can also be placed deliberately, to fingerprint a document or to disguise a file name or a line of code with the right-to-left override (U+202E).
The symptoms are familiar once you know the cause. A password or coupon code that looks right is rejected. A search fails to find a word that is plainly on the page. A link breaks and the address bar shows %E2%80%8B, the encoded form of a zero-width space. A script stops with an error such as Python's invalid non-printable character U+200B.
How the detector decides what is hidden
The detector matches a fixed list: the soft hyphen, the combining grapheme joiner, the Arabic letter mark, the zero-width characters and direction marks from U+200B to U+200F, the embedding and override controls from U+202A to U+202E, the word joiner and invisible operators from U+2060 to U+2064, the format controls from U+2066 to U+206F, the byte order mark, the braille blank, the Hangul fillers, two Khmer inherent vowels and the Mongolian vowel separator.
It does not flag characters that are legitimately spaces. A no-break space or an em space taken from the copy list is neither reported nor removed, and the same goes for tabs, other wide or thin spaces and line breaks. Position is a zero-based offset in UTF-16 code units, the index JavaScript uses, so an emoji earlier in the text counts as two.
Limits and neighbouring tools
The check runs in the page and the pasted text is not sent anywhere. It finds characters, not intent: it cannot say who inserted a zero-width space or why. Lookalike letters, such as a Cyrillic a inside a Latin word, are visible and outside its scope. For domain names the Punycode Converter exposes them. If a character count looks too high for the visible text, the Word Counter counts every code point, hidden ones included.