StegoToolkit

Unicode Steganography Hider

Hide secret messages in plain text using 4 Unicode methods: Zero-Width Binary, ZW-V2, Homoglyph, or Variation Selectors. Optional AES-256-GCM encryption. Processed in your browser, not uploaded.

AES-256 Encryption
4 Methods
In-browser

Enter Your Cover Text

The visible text that will contain your hidden message

Try the demo instantly

No upload needed — loads a sample file

Enter at least 10 characters

Processed in your browser

Your text is processed in this browser tab and not sent to a server. Usage statistics may record which options were used, never your text.

How to Hide a Message in Plain Text (5 steps)

  1. Enter your cover text — the visible message your secret will hide inside.
  2. Type your secret message in the payload field.
  3. Choose a method: Zero-Width Binary (simple), ZW-V2 (more compact), Homoglyph (changes letters instead of adding invisible characters), or Variation Selector (needs emoji in the cover text).
  4. Add a password to encrypt the payload (optional but recommended).
  5. Click 'Hide Message' — copy the output and send it normally.

Unicode Steganography Methods Comparison

MethodTechniqueCapacityBest For
Zero-Width BinaryZWSP (U+200B) = 0, ZWNJ (U+200C) = 1~1 byte per 8 visible charactersThe simplest method; works on any cover text
Zero-Width V28 ZW chars, 3 bits per symbol~3 bytes per 8 visible charactersShorter output for the same message
HomoglyphLatin → Cyrillic lookalike substitution~1 bit per substitutable charVisible letters change; no invisible characters (copy-paste and per-service survival not tested)
Variation SelectorU+FE00–U+FE0F after emoji~0.5 byte per emoji (a sequence such as a family counts once)Covers that already contain many emoji

What This Tool Hides, and Where

The carrier is plain text that you paste or load from a .txt file, in any language. The hidden payload is typed text or a file of up to about 1 MB after encryption and error correction. The output is text again, to be copied, not a new file format.

Four methods, each a different place to put bits. Zero-Width Binary inserts U+200B (bit 0) or U+200C (bit 1) between visible characters. Zero-Width V2 uses eight different invisible characters, three bits per character. Homoglyph swaps Latin letters for Cyrillic look-alikes, one bit per letter. Variation Selector adds one of the sixteen selectors U+FE00 to U+FE0F after each emoji, four bits per emoji.

All four write the same wire format: a 32-bit header (the top bit says whether the data is encrypted, the other 31 bits are the length in bytes) followed by the data. Variation Selector writes it as 4-bit values, the others as bits.

Choosing a Method

Zero-Width Binary and Zero-Width V2 work on any text. V2 needs about a third as many characters for the same message. Homoglyph needs no invisible characters but changes letters, and it is limited by how many Latin letters from the table below the cover has. Variation Selector needs emoji in the cover.

The look-alike letters are real Cyrillic code points, so a spell checker, a search for a word you hid, or a check that compares scripts will notice them. The invisible characters are found by any tool that lists code points. Nothing here is hidden from someone who looks for it.

For zero-width characters in text with platform-specific character sets, see the Invisible Text Hider. For spaces, tabs and line endings instead of invisible characters, see the Whitespace Steganography Hider; for hiding in HTML source, the HTML Steganography Hider.

Password, Error Correction and Size

A password encrypts the data with AES-256-GCM before it is written; the key comes from PBKDF2 with 100,000 iterations. Encryption adds 48 bytes. It hides the content, not the fact that invisible characters, look-alike letters or selectors are there.

Reed-Solomon (available in the most detailed mode) adds a 16-byte header plus 10, 20 or 30 parity bytes for every 223 data bytes (rs-10, rs-20, rs-30) and repairs up to 5, 10 or 15 changed bytes per block. It repairs changed characters, for example a bit flipped to its opposite. It cannot restore characters that were deleted, and the 32-bit header is not covered by it.

There is no compression step. The Extractor accepts at most 1,000,000 stored bytes, and the Hider refuses a message that would exceed that.

What Is Changed in Your Cover Text

Characters are inserted between whole visible characters: an emoji sequence such as a family, a flag, a letter with its accent marks, or a Windows line ending is never split. Zero-Width V2 never inserts before the first character, because U+FEFF is also the byte-order mark and a file that starts with it can lose it when saved.

If the cover already contains characters the method reads as data, the tool removes them first and tells you how many: U+200B and U+200C for Zero-Width Binary; all eight V2 characters, including U+200D, for V2 (U+200D can break emoji ZWJ sequences and may affect scripts or text that use the joiner; the tool reports how many characters it removes); and variation selectors for Variation Selector, which can change how a heart or check mark displays. Homoglyph refuses a cover that already contains Cyrillic look-alikes.

Capacity by Method for Two Covers

Cover A is the sentence "The quick brown fox jumps over the lazy dog near a calm river today. " (69 characters) repeated 20 times: 1,380 characters, 520 of them Latin letters that have a look-alike, no emoji. Cover B is cover A followed by 100 copies of "😀 ": 1,580 visible characters and 100 emoji. The tool counts the slots S. The largest message without a password is floor(S × bits per slot ÷ 8) − 4, where the 4 bytes are the 32-bit header. Zero-Width Binary has S = 1,380 on cover A (floor(1,380 ÷ 8) − 4 = 168); Zero-Width V2 uses 3 bits per slot and never the first position, so S = 1,379 (floor(1,379 × 3 ÷ 8) − 4 = 513). Homoglyph counts only the Latin letters in the look-alike table, not all characters, and Variation Selector counts emoji (floor(100 × 4 ÷ 8) − 4 = 46). A password uses another 48 bytes of the stored data, so the figures in brackets are 48 lower.

MethodSlotCover A largest (with password)Cover B largest (with password)
Zero-Width Binary1 bit per visible character168 B (120 B)193 B (145 B)
Zero-Width V23 bits per visible character, never before the first513 B (465 B)588 B (540 B)
Homoglyph1 bit per Latin letter in the table61 B (13 B)61 B (13 B)
Variation Selector4 bits per emojinone (no emoji)46 B (none: a password needs 48 B for encryption alone)

Payload Storage Before the 32-Bit Header

Bytes of stored data for a 100-byte message, before the 32-bit header. Add another 4 bytes for the shared length and encryption-flag header to get the total the method must carry:

SettingsBytes stored
No password, no Reed-Solomon100
Password148
Reed-Solomon rs-10126
Reed-Solomon rs-20136
Reed-Solomon rs-30146
Password and rs-20184

The Eight Zero-Width V2 Symbols

Value (3 bits)CharacterCode point
000Zero Width SpaceU+200B
001Zero Width Non-JoinerU+200C
010Zero Width JoinerU+200D
011Word JoinerU+2060
100Invisible TimesU+2062
101Invisible SeparatorU+2063
110Invisible PlusU+2064
111Zero Width No-Break SpaceU+FEFF

The Look-Alike Letters (Homoglyph)

A Latin letter stays as it is for a 0 bit and is replaced by the Cyrillic letter for a 1 bit. Only these 23 letters carry bits.

Latin lettersCyrillic replacements
a e o p c x yU+0430 U+0435 U+043E U+0440 U+0441 U+0445 U+0443
A B C E H K M O P T XU+0410 U+0412 U+0421 U+0415 U+041D U+041A U+041C U+041E U+0420 U+0422 U+0425
i I S j sU+0456 U+0406 U+0405 U+0458 U+0455

Measured: Normalisation

The result of Unicode normalisation on a message hidden in cover A (Node.js, one message of 2 bytes per method). Nothing else was measured: individual websites, apps, fonts and sanitisers were not tested.

MethodNFCNFKC
Zero-Width BinaryReadableReadable
Zero-Width V2ReadableReadable
HomoglyphReadableReadable
Variation Selector (cover B)ReadableReadable

Examples

Input: Hide "Hi" (2 bytes) in cover A with Zero-Width Binary.

Result: 48 invisible characters are inserted: the 32-bit header (it holds the length 2) and 16 bits for H and i. The text grows by 48 characters and 144 bytes in UTF-8.

Meaning: Each hidden bit is one inserted character of 3 bytes. The positions are chosen with a seed, and the Extractor needs no seed because it reads every U+200B and U+200C in order.

Input: The same message with Zero-Width V2.

Result: 16 characters are inserted, 48 bytes in UTF-8: 48 bits in groups of 3. Four of the 16 are outside U+200B and U+200C.

Meaning: V2 packs three bits per character, which is why it holds about three times as much per character.

Input: The same message with Homoglyph.

Result: The text keeps its length. 7 of the first 48 Latin letters in the table are replaced by Cyrillic ones, one for each 1 bit.

Meaning: The 32-bit header has one 1 bit (the length 2), H has two and i has four. Letters for 0 bits are untouched.

Input: The same message with Variation Selector in cover B.

Result: 12 emoji get a selector: U+FE00 seven times and U+FE02 for the header, then U+FE04 U+FE08 U+FE06 U+FE09 for H (0x48) and i (0x69).

Meaning: Each nibble of the header and the data is the selector's number from FE00. The text length grows by 12 characters.

Input: Text with 60 red hearts (the heart plus its emoji-style selector).

Result: The scan counts 60 variation selectors and calls Variation Selector the likely method, but nothing decodes.

Meaning: Selectors that were already in the text look like a message to the scan. The Extractor needs a valid header after them to report one.

Input: A cover that already has Cyrillic letters, hidden with Homoglyph.

Result: The Hider stops and says the text already contains Cyrillic look-alikes.

Meaning: The Extractor would read each of them as a 1 bit, so the tool does not write a message it cannot read back.

How the Unicode Hider Works

1. Prepare the cover

Characters the method would read as data are removed and counted. Homoglyph refuses a cover with Cyrillic look-alikes. The slots are counted per visible character, per Latin letter in the table, or per emoji.

2. Build the data

A password encrypts the message (AES-256-GCM); a Reed-Solomon level adds parity. A 32-bit header with the encrypted flag and the length is put in front.

3. Write the slots

Zero-Width Binary and V2 insert characters at positions picked by a seeded random generator (the seed is saved in the settings link and is not needed to read). Homoglyph and Variation Selector use the first slots in reading order.

4. Read it back

The finished text is read with the Extractor's own code and compared with what was meant to be hidden. If it differs, no output is produced.

5. Copy the text

Copy the result exactly. A paste-back check lets you paste the text as it arrived from the place you sent it to and reports how many of the characters survived.

What the results mean

ResultWhat it meansWhat to do
Method, Hidden, EncryptedThe method, the number of bytes you hid, and AES-256-GCM when you set a password.None for Encrypted means anyone with a decoder can read it.
Chars insertedInvisible characters or selectors added; for Homoglyph, the letters that were replaced.It is the number of slots used: 48 for a 2-byte message with Zero-Width Binary.
Notes on the coverHow many characters were removed from your cover text before writing (zero-width characters, ZWJ, variation selectors).Compare the output with your original if the text had emoji sequences.
Platform CompatibilityEvery service is listed as not tested. This site has no per-service result.Use the paste-back check on the place you will send the text.
Verify the outputDecodes the text just produced and compares the bytes with your message. With a password, it can confirm the data is present without decrypting it.A failure here means the Hider's own output cannot be read: report it.
Paste-back checkReads text you pasted back from the destination and reports how many characters are intact.Some loss means the destination removed or changed some of the characters; try another method.
Settings link and config fileA link that pre-fills method and seed, and a JSON file of the settings.The seed controls character placement only. It is not an encryption key and is not needed to read the message.
Watermark batchOne copy per recipient (up to 200) with a different ID, plus a separate key file.A copy that could not be made is not in the ZIP and is listed in the key file.

Limitations

  • Nothing here is undetectable. Invisible characters appear in any code point listing, look-alike letters appear in any check that compares scripts, and selectors appear in any listing of U+FE00 to U+FE0F. No detection tool was tested.
  • Survival through websites, messengers, email, word processors and sanitisers was not tested. By design, anything that removes invisible characters, normalises letters or rewrites emoji destroys what it touches.
  • In our test, NFC and NFKC normalisation left all four methods readable (see the measured table). Other transformations were not tested.
  • Variation Selector writes U+FE00 to U+FE0F. U+FE00 to U+FE0D are the other selectors, U+FE0E asks for text presentation and U+FE0F for emoji presentation, so 2 of the 16 values (on average 1 nibble in 8) change how an emoji may be drawn, and not every renderer respects selectors. We did not test renderers.
  • Reed-Solomon repairs changed characters, not deleted ones, and does not cover the 32-bit header.
  • Zero-Width V2 removes U+200D from your cover before embedding. This can break emoji ZWJ sequences and may affect scripts or text that use the joiner. The tool reports how many characters it removes. Variation Selector replaces selectors in your cover.
  • The tool stores at most 1,000,000 bytes after encryption and error correction. A cover of a few megabytes is processed in a few seconds.

Privacy

Your text is processed in your browser tab; the tool's own code does not upload it. Usage statistics may record which options were used and coarse facts such as sizes, never your text or message. The Platform Compatibility list is a reminder that no service was tested, not a test.

Which Tool Next?

Frequently Asked Questions

What is Unicode steganography?

This tool hides data inside ordinary-looking text with invisible Unicode characters (zero-width characters, variation selectors after emoji) or look-alike letter substitutions (Latin letters swapped for Cyrillic ones). The text reads the same to a person, but its code points differ, so it is not identical to a computer.

Which method should I use?

Zero-Width Binary is the simplest choice and works on any cover text. If an app removes invisible characters, Homoglyph is worth trying because it uses letters instead of invisible characters. We have not tested Twitter/X, Facebook, SMS or any other service, so use the check on the result page: paste the text back from where you sent it and see whether it still decodes.

Can Twitter strip my hidden message?

Possibly — some apps remove zero-width characters, but we have not tested Twitter/X or Facebook specifically. Homoglyph does not use zero-width characters, so a stripper aimed at them would not affect it, but spam and anti-phishing filters that look for Cyrillic look-alikes could. Test with the check on the result page.

Is this real encryption or obfuscation?

The AES-256-GCM option is real encryption (key from your password with PBKDF2, 100,000 iterations). Without a password, anyone who runs a decoder can read the hidden message. With a password the content cannot be read without it, but the characters that carry it can still be seen by a scanner. Encryption protects the hidden content, not the existence of the embedded data. The key derivation uses a fixed 100,000 PBKDF2 iterations, so an attacker who has the text can guess passwords offline; use a long, unique passphrase.

How is this detected?

Zero-width methods show up in any Unicode scanner or hex view. Homoglyph needs a code-point comparison (mixed Latin and Cyrillic letters in one word is a well-known check), so it is not undetectable. We did not test detection tools. Encryption hides the content, not the fact that something is hidden.

Related Tools