Every few weeks someone asks the same question in a different costume: how do I send an empty message on WhatsApp, how do I make my Free Fire name invisible, why does my Instagram bio lose its blank lines. The answer is the same each time, and it is not a trick inside any of those apps. It is Unicode.
A space is not a character. To an app, it is a separator.
When you type a name, a message or a bio, the app trims it before saving. Leading and trailing whitespace goes, runs of spaces collapse, and a field that contains only spaces becomes an empty string. Then the validation runs: empty name, empty message, rejected.
So "invisible text" cannot be made of spaces. It has to be made of characters that render as nothing but are not whitespace to the trimming code. Unicode has several, and they were never designed for this. Each exists for a real typographic or scripting reason, which is exactly why every app treats them differently.
The five that matter, and what each was for
| Character | Code point | Why it exists | Who keeps it |
|---|---|---|---|
| Hangul Filler | U+3164 |
A placeholder in Korean syllable composition — a "letter" that draws nothing | Game nickname fields (Free Fire, PUBG Mobile), Instagram name and bio, TikTok nickname |
| Braille Pattern Blank | U+2800 |
The braille cell with no dots raised — a printable glyph that is empty | WhatsApp, Telegram and Discord messages, Instagram comments |
| Zero-Width Space | U+200B |
A line-break opportunity with no width, for scripts without spaces | X posts, Apple Notes, HTML; stripped by most chat apps |
| Invisible Separator | U+2063 |
Marks an invisible boundary between items (think matrix indices) | Facebook and Messenger |
| Hair Space | U+200A |
The thinnest typographic space | Word, Google Docs, email |
The pattern is not random. Hangul Filler is a letter (category Lo), so a name validator that asks "does this contain at least one letter?" says yes. Braille Blank is a symbol (So) — printable, so a "message must not be empty" check passes. Zero-Width Space is a format character (Cf), and format characters are the first thing a sanitiser strips, which is why it fails in WhatsApp and works in a text editor.
If you want to see the categories yourself:
for (const ch of ['ㅤ', '⠀', '', '', ' ']) {
const cp = ch.codePointAt(0).toString(16).toUpperCase().padStart(4, '0');
console.log(`U+${cp}`, /\p{L}/u.test(ch) ? 'letter' : /\p{S}/u.test(ch) ? 'symbol' : /\p{Cf}/u.test(ch) ? 'format' : /\p{Zs}/u.test(ch) ? 'space' : 'other');
}
// U+3164 letter · U+2800 symbol · U+200B format · U+2063 format · U+200A space
Why an invisible name breaks after an update
A game that once accepted U+3164 and now rejects it did not "patch invisible names". Somebody added a Unicode normalisation or a category filter to the name validator — usually to stop impersonation, because two names that look identical but differ by an invisible character are a moderation nightmare. The moment a validator runs NFKC normalisation, U+3164 becomes U+1160 (Hangul Jungseong Filler) or is dropped entirely, and U+FFA0 (the halfwidth form) folds into the same thing.
That is why any honest invisible-text tool offers several characters instead of one, and says which app each survives. It is also why "test on your own account before spending a rename card" is the only advice that stays true across updates.
Detecting it is trivial, which is the point
Invisible does not mean hidden. Paste the text into anything that counts characters and the count gives it away:
const INVISIBLE = new Set([0x200B, 0x200C, 0x200D, 0x2060, 0xFEFF, 0x2800, 0x3164, 0xFFA0, 0x2063, 0x200A, 0x00A0]);
const report = (s) => {
let invisible = 0;
for (const ch of s) if (INVISIBLE.has(ch.codePointAt(0))) invisible++;
return { total: [...s].length, invisible };
};
report('abㅤ⠀'); // { total: 4, invisible: 2 }
Two details that bite: iterate with for…of, not .length — .length counts UTF-16 code units, so an emoji is 2 and a family emoji is 11, and your "invisible" count drifts. And normalise after counting if you must normalise at all; s.normalize('NFKC') removes the very characters you are trying to find.
The other kind: text that carries a message nobody can see
There is a second, unrelated trick that gets called "invisible text" too. Zero-width characters come in pairs that a program can tell apart — U+200B and U+200C — so a string of them can carry bits. Encode each byte of a message as eight zero-width characters, wrap the run in a visible carrier so the chat app accepts it, and the recipient pastes the "empty" message back into the same page to read it. It is steganography, not encryption: anyone with the decoder reads it. The ghost text page does exactly that, and the newer invisible text page is the plain-blank version — one tap copies the character an app keeps, and a checker box tells you whether what you pasted really contains one.
Both run in the browser. There is nothing to upload; the "tool" is a clipboard write of a string the page already holds.
Practical summary
- Blank message in WhatsApp, Telegram, Discord:
U+2800. - Blank name or bio line in Instagram, TikTok, Free Fire, PUBG:
U+3164(fallbackU+FFA0). - Blank post on X or a hidden line in Notes:
U+200B. - Facebook / Messenger:
U+2063. Documents and email:U+200A. - Nothing works in a field that validates against
[a-z0-9._]— Instagram and Discord usernames — and no tool can change that.
If you maintain a name field and want to stop this: normalise with NFKC, then reject anything that is empty after removing \p{Cf}, \p{Zs} and the two Hangul fillers. Say so in the error message, because "invalid name" sends people straight back to the tools above.
Top comments (0)