# ECI: how QR codes declare a character encoding

> ECI (Extended Channel Interpretation) is an optional header (mode indicator 0111 plus a numeric designator) that declares how byte-mode data should be interpreted. UTF-8 is ECI 26 and ISO-8859-1 is ECI 3. Most modern decoders assume UTF-8 even without it, while some older readers fail on ECI headers entirely.

Source: https://useqr.app/docs/spec/eci-extended-channel-interpretation · Last reviewed 2026-08-21 · UseQR is free forever, no signup.

---

## The problem ECI solves

[Byte mode](/docs/spec/data-encoding-modes) stores octets, not characters. The bytes
`0xC3 0xA9` are `é` in UTF-8, `Ã©` in ISO-8859-1 and something else again in Shift-JIS,
and nothing in the base symbol says which reading is intended. QR's original 1990s context
assumed Japanese 8-bit conventions; the wider world needed a way to label the payload.

[ECI](/glossary/eci) is that label: a header that switches the "channel interpretation"
for everything after it.

## The wire format

An ECI header is the mode indicator `0111` followed by a designator whose length depends
on its value:

| Designator value | Encoding of the designator |
|---|---|
| 0–127 | 8 bits: `0xxxxxxx` |
| 128–16383 | 16 bits: `10xxxxxx xxxxxxxx` |
| 16384–999999 | 24 bits: `110xxxxx …` |

The header sits *before* the data segment it modifies, and the assignments that matter in
practice are few:

| ECI | Interpretation |
|---|---|
| 3 | ISO-8859-1 (Latin-1) |
| 20 | Shift-JIS |
| **26** | **UTF-8** |

So a UTF-8-labelled payload costs 12 extra bits: `0111` + `00011010`.

## The awkward truth: mostly nobody uses it

The standard's default interpretation for byte mode without ECI is ISO-8859-1 (earlier
editions pointed at JIS 8-bit conventions). Reality diverged years ago:

- **Most encoders emit plain UTF-8 bytes with no ECI header.** It saves 12 bits and, more
  importantly, avoids compatibility risk.
- **Most decoders sniff.** UTF-8 has a distinctive byte structure (invalid sequences are
  statistically obvious), so libraries like [ZXing](/glossary/zxing) try UTF-8 first and
  fall back. Phone cameras behave the same way.

The result is a de facto standard (UTF-8, unlabelled) sitting on top of a de jure one.
For URLs and any ASCII payload the question never arises, since ASCII is identical in all
the candidate encodings.

## When ECI actually breaks things

ECI is where "standards-compliant" and "works everywhere" part ways:

- **Old and minimal readers** (early dedicated scanners, embedded firmware, quick
  hand-rolled decoders) may not implement ECI at all. Some fail the whole scan on the
  unknown mode indicator `0111`; others emit the raw designator bytes as garbage
  prepended to your data.
- **Hardware wedge scanners** in warehouses translate scans to keystrokes and can mangle
  ECI-switched payloads; test with the actual devices: see
  [hardware barcode scanners and QR](/docs/scanning/hardware-barcode-scanners-and-qr).
- **Non-UTF-8 designators** (Cyrillic code pages, UTF-16) are supported so unevenly that
  the honest advice is: do not ship them.

Practical guidance: encode UTF-8, skip the ECI header unless a system on the *reading*
side specifically requires it, keep mission-critical payloads ASCII where possible, and
[verify decoding with a real decoder](/validate) rather than assuming. This is what UseQR
does: payloads are encoded as raw UTF-8 in byte mode, no ECI header, matching what phone
cameras expect.

## FAQ

### What is ECI in a QR code?
Extended Channel Interpretation, an optional header (mode indicator 0111 plus a numeric designator) that declares how the byte-mode payload should be interpreted. ECI 26 means UTF-8, ECI 3 means ISO-8859-1, ECI 20 means Shift-JIS.

### Do I need an ECI header for UTF-8?
Formally yes, practically no. Nearly all modern decoders assume or detect UTF-8 without the header, and nearly all encoders omit it. Adding it costs 12 bits and risks confusing older readers that never implemented ECI.

### What is the default encoding of a QR code without ECI?
The standard says ISO-8859-1 (earlier editions implied JIS 8-bit conventions), but real-world decoders overwhelmingly try UTF-8 first because its byte patterns are easy to detect. For pure ASCII payloads such as URLs, every candidate encoding reads identically.

### Why does my QR code show strange characters on some scanners?
An encoding mismatch: the payload's bytes are being interpreted with the wrong character set, or an unhandled ECI header is leaking into the output. Re-encode as plain UTF-8 without ECI and test on the scanners your audience uses.

## Try it

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