Also available in: Español · Português · Français · العربية
Character Encodings: Every Charset a Browser Knows
The complete list a browser must support, a decoder that runs in yours, and what a label really resolves to.
What is a character encoding?
A file holds bytes. A character encoding is the agreement that turns those bytes into letters — that byte 0x41 is A, that the two bytes 0xC3 0xA9 are é. Get the agreement wrong and you get mojibake: the same bytes read through the wrong table, producing é where é was meant.
There used to be hundreds of these agreements, one per language and vendor. The web narrowed them: the WHATWG Encoding Standard lists exactly 40 encodings and the 228 labels that name them, and it is the rare list that cannot grow. Its own words are that the table lists all encodings and labels user agents must support, and that user agents must not support any other. One of the 40 is current. The remaining 39 sit under headings beginning with the word Legacy.
That closure is the difference between this list and every registry it looks like. A registry records what exists and gains rows. This one is a ceiling.
How to use it
- Put some bytes in. Hex digits are read as bytes, so 93 77 6f 72 6c 64 94 is seven of them. Anything else is treated as text and encoded as UTF-8 first, because UTF-8 is the only thing a browser can encode.
- Name an encoding. Any of the 228 labels works, in any case. An unrecognised label is a failure rather than a silent fall back, which is what the standard requires.
- Read the comparison underneath. The same bytes are decoded under four different labels that all resolve to one encoding, so the four rows come out identical — which is the point.
There is no ASCII encoding, and no Latin-1 either
Ask a browser for ascii and you get windows-1252. Ask for us-ascii, iso-8859-1, latin1, cp819 or ansi_x3.4-1968 and you get windows-1252 again. Seventeen of the 228 labels are piled on that one row, and neither ASCII nor ISO-8859-1 exists in the standard under its own name — while ISO-8859-2 and ISO-8859-15 both do, which makes the missing one a decision rather than an oversight.
It matters because windows-1252 is not ISO-8859-1. Decoding all 256 byte values under both definitions, they differ on 27 of them, and every one of those 27 sits in the range 0x80 to 0x9F, which ISO-8859-1 fills with invisible control codes and Microsoft filled with punctuation. Byte 0x80 is the euro sign. 0x91 to 0x94 are the curly quotes. 0x96 and 0x97 are the en dash and em dash. 0x85 is the ellipsis.
So the characters where the two disagree are exactly the ones a word processor inserts without being asked, which is why a document saved as Latin-1 and served as Latin-1 still shows the right quotation marks — the browser was never using Latin-1. Five of the byte values Microsoft left empty stay as control characters rather than becoming U+FFFD, so nothing in that range ever fails to decode.
This also puts a bound on how much a single-byte encoding can be trusted to be total: across the 28 single-byte encodings, 150 byte slots have no character at all and decode to U+FFFD, spread over nine of them. Every byte being a character is a reasonable assumption and a false one.
Read forty, write one
A browser will decode all 40 of these. It will encode exactly one. The standard specifies the encoding property of a text encoder to be utf-8, and gives its constructor no argument at all, so there is no supported way to ask a browser to write Shift_JIS or windows-1251. Section 4.3 pushes the same rule further out: when URL parsing or form submission needs an output encoding, replacement and both UTF-16 encodings are rewritten to UTF-8 before anything is written.
One entry is stranger than the rest. The encoding named replacement decodes nothing: any non-empty input becomes a single U+FFFD. Six labels point at it, five of them real, deployed encodings — ISO-2022-CN, ISO-2022-KR, HZ-GB-2312 and their aliases. The standard says plainly why: it exists to prevent attacks that abuse a mismatch between the encodings a server supports and the ones a client does. ISO-2022-JP survived the same cull only because too much content depends on it.
One label answers a question people ask and get wrong: utf-16, with no endianness attached, means little-endian. So does the label unicode.
What this page cannot tell you
The decoder here is your browser's, not ours, which is deliberate — it is the only implementation whose answer matters to you, and it is the one the standard is written for. It also means the results can differ from another runtime. Node, for instance, refuses the replacement encoding outright even though the standard requires support for it, so a decode that works here may not work in a script.
Second, this page tells you what a label means, not what a file is. Nothing in a sequence of bytes says which encoding produced it; guessing is a separate and much harder problem, and the honest answer for any file you control is to convert it to UTF-8 and stop guessing.
Third, the standard is a web standard. Databases, terminals and programming languages implement their own tables, and they do not always agree. Compared byte by byte against Python's codecs across all 28 single-byte encodings, 18 are identical and the rest differ on 89 of 7,168 byte positions — mostly where Python refuses a byte Microsoft left undefined and a browser hands back a control character instead. One real disagreement remains, at two positions in KOI8-U, where the two projects inherited different versions of the same encoding.
Why is it free?
The table is a few kilobytes shipped with the page, and the decoding is done by the browser you already have. Nothing you type is uploaded, nothing is logged, and there is no account to make.
No sign-up, no limits, and no watermark on anything you copy out.