# UTF-8 and Unicode in QR codes: emoji, CJK and the legacy trap

> QR codes carry Unicode by encoding text as UTF-8 in byte mode: emoji, CJK and accented characters all work on modern phone scanners without an ECI header. The costs: each character takes 1–4 bytes (an emoji is typically 4), and some legacy readers wrongly assume Shift-JIS and show garbled text.

Source: https://useqr.app/docs/spec/utf-8-and-unicode-in-qr-codes · Last reviewed 2026-08-21 · UseQR is free forever, no signup.

---

## How Unicode gets into a QR code

There is no "Unicode mode". [Byte mode](/docs/spec/data-encoding-modes) stores whatever
octets you give it, so the universal recipe is: encode the string as **UTF-8**, store the
bytes, and rely on the decoder to interpret them as UTF-8, which every current iOS and
Android camera does by default. No [ECI header](/docs/spec/eci-extended-channel-interpretation)
needed in practice.

That means a QR code can carry `Grüße aus Köln`, `東京タワー`, `مرحبا`, or `I ♥ QR 🎉`
(any Unicode text) subject only to capacity.

## What Unicode costs

UTF-8 is variable-width, and QR capacity is counted in **bytes**, not characters:

| Characters | UTF-8 bytes each | Bits in the symbol |
|---|---|---|
| ASCII (URLs, A–Z, digits) | 1 | 8 |
| Latin accents (é, ü, ñ) | 2 | 16 |
| CJK, most scripts | 3 | 24 |
| Emoji (🎉 = U+1F389) | 4 | 32 |

A 100-character Japanese message is ~300 bytes, the size of a 300-character English one.
An emoji costs four times an ASCII letter, and composed emoji (skin tones, families) chain
multiple code points: 👨‍👩‍👧 is **18 bytes**. Capacity ceilings are byte ceilings:
[2,953 bytes at version 40-L](/docs/reference/qr-code-capacity-table) is only ~980 CJK
characters or ~730 emoji. For dense text, [Kanji mode](/docs/spec/kanji-mode-explained)
can beat UTF-8 for pure Japanese, at a compatibility price.

## The legacy Shift-JIS trap

QR codes were designed at [Denso Wave](/glossary/denso-wave) in 1994 for Japanese
industry, and the original byte-mode assumption was JIS/Shift-JIS text. Consequences that
survive today:

- **Old Japanese-market readers** (and some embedded decoders derived from them)
  interpret unlabelled bytes as Shift-JIS. Your UTF-8 `café` renders as mojibake.
- **Some decoders sniff and guess wrong** on short, ambiguous payloads, a few bytes of
  accented Latin-1 can also be valid Shift-JIS, and the guess goes to the wrong one.
- The reverse trap exists too: text encoded as Shift-JIS by a Japanese generator shows
  garbled on a UTF-8-assuming Western app.

For URLs none of this matters: ASCII is identical in every candidate encoding, which is
one more reason payloads that *must* work everywhere should be a plain ASCII URL with the
interesting content behind it.

## A real implementation bug worth knowing

Unicode handling is where QR libraries quietly go wrong. A concrete example from UseQR's
own stack: the underlying `qrcode-generator` library's default string handling keeps only
the **low byte of each JavaScript character code**: multi-byte characters are silently
mangled. UseQR pre-expands every string into its UTF-8 octets before encoding, so `東京`
or an emoji arrives intact. If you use a QR library directly, test a non-ASCII payload
and [decode the output](/validate) before trusting it. This class of bug produces codes
that look perfect and scan to garbage.

The same caution applies to [WiFi passwords](/docs/troubleshooting/wifi-qr-special-characters-escaping)
and [vCards](/docs/troubleshooting/vcard-qr-code-imports-wrong), where special characters
meet format-specific escaping rules on top of the encoding question.

## FAQ

### Can a QR code contain emoji?
Yes. Emoji are encoded as UTF-8 in byte mode (typically 4 bytes each, more for composed sequences), and modern phone scanners display them correctly. They work in text payloads; inside URLs they must additionally be percent-encoded.

### Does a QR code support Chinese, Japanese and Korean text?
Yes, as UTF-8 at 3 bytes per character, readable by all current phone cameras. For pure Japanese text, kanji mode stores Shift-JIS characters in 13 bits instead of 24, but with narrower generator and reader support.

### Why does my QR code show garbled characters?
Almost always an encoding mismatch: the bytes are UTF-8 but the reader assumed Shift-JIS or Latin-1, or the generator mangled multi-byte characters before encoding. Regenerate as clean UTF-8 and test on the scanners your audience actually uses.

### Do special characters make a QR code bigger?
Yes. Any non-ASCII character forces byte mode and costs 2–4 bytes in UTF-8, so accented or CJK text reaches a given QR version sooner than plain ASCII. Capacity limits are counted in bytes, not characters.

## Try it

- https://useqr.app/text
- https://useqr.app/url
- https://useqr.app/validate
