é is C3 A9: how many bytes a character takes in UTF-8
A UTF-8 hex conversion turns text into the bytes a computer really stores, and writes each byte as two hexadecimal digits from 00 to FF. The letter é has the Unicode number (code point) U+00E9 and becomes the two bytes C3 A9. A plain A is the single byte 41, and the emoji 😀 is the four bytes F0 9F 98 80. Going the other way, paste C3 A9 from a log or a debugger and you get é back.
Both boxes above are editable, and whichever one you change becomes the source. The strip in the middle prints each character with its own bytes underneath, like captions, and a colour under each byte shows whether the character takes 1, 2, 3 or 4 bytes. Click a character and the bit lens shows which bits of its code point land in which UTF-8 byte. Hex can be written space-separated, joined, as a 0x array, as \x escapes or as % encoding, and when you paste, all five are understood.
When you need to see the UTF-8 bytes
- A log shows \xc3\xa9 where a letter should be: Python prints bytes outside ASCII as \x escapes, so café stored as UTF-8 appears as b'caf\xc3\xa9'. Paste that whole line into the hex box, quotes and the plain letters included, and the converter reads it back as café.
- MySQL refuses an emoji: utf8mb3 (formerly just utf8) stores at most 3 bytes per character, so a 4-byte character such as an emoji fails with error 1366 and a message like Incorrect string value: '\xF0\x9F\x98\x80'. Paste the bytes into the converter and you see one 😀 that needs four bytes.
- Two strings look identical but do not match: a non-breaking space (C2 A0), a zero-width space (E2 80 8B) and a byte order mark at the start of a file (EF BB BF) are invisible on screen but different in bytes. The strip labels them NBSP, ZWSP and BOM.
- A file name with an accent will not match: a Mac volume formatted as HFS Plus stores file names in a variant of decomposed form (NFD), so café.txt can arrive as c, a, f, e and a separate accent. It grows from 9 to 10 bytes, and the converter tells you what NFC would make of it.
- Reading %C3%A9 in an address: a URL carries non-ASCII text by converting it to UTF-8 first and writing each byte as % plus two hex digits. Paste %63%61%66%C3%A9 and café comes out.
- Putting a string into a byte array in code: embedded firmware and wire protocols often want 0x63, 0x61, 0x66, 0xC3, 0xA9. Choose the "0x array" format and the converter writes it in a form you can paste straight into the source.
- Curly quotes or accents turned into strange letters: text such as “café” that shows up as café or “ means UTF-8 bytes were read as Windows-1252, or the other way round. Put the original bytes in the hex box and the converter shows whether they are valid UTF-8 and what they look like in Windows-1252.
How to use it
- Type text into the text box, or paste bytes into the hex box. The page opens with an example, and the buttons above load hidden characters, a decomposed accent, \x bytes from a log and broken bytes.
- The arrows between the boxes show the direction. Edit the text box and the conversion runs downward (encode); edit the hex box and it runs upward (decode).
- Pick a hex format and upper or lower case. If hex is already in the box, changing the format rewrites the same bytes in the new style.
- Click a character in the strip, or move the cursor in a box, and the bit lens shows its code point, its UTF-8, UTF-16 and Windows-1252 bytes and its byte offset.
- Use "Copy hex" or "Copy text" to take the result away. The panel at the lower right compares how many bytes the same text takes in UTF-16 and Windows-1252.
How UTF-8 splits a character into bytes
UTF-8 writes every character from U+0000 to U+10FFFF as 1 to 4 bytes (RFC 3629). The first byte starts with bits that tell you how many bytes the character has, and every following byte starts with 10. From any single byte you can therefore tell whether it begins a character or continues one.
| Code point range | Bytes | Bit pattern | Example |
|---|---|---|---|
| U+0000 to 007F | 1 | 0xxxxxxx | A → 41 |
| U+0080 to 07FF | 2 | 110xxxxx 10xxxxxx | é → C3 A9, Ω → CE A9 |
| U+0800 to FFFF | 3 | 1110xxxx 10xxxxxx 10xxxxxx | € → E2 82 AC, 日 → E6 97 A5 |
| U+10000 to 10FFFF | 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 😀 → F0 9F 98 80 |
Take € and do it by hand. U+20AC in binary is 0010 0000 1010 1100, sixteen bits. The 3-byte pattern has room for 4 + 6 + 6 bits, so split it as 0010 / 000010 / 101100 and put the pieces into 11100010, 10000010, 10101100. Those three bytes are E2, 82 and AC in hex. For U+0000 to 007F the byte is the code point itself, so text made only of English letters, digits and punctuation has exactly the same bytes in ASCII and in UTF-8.
The accented letters of Western European languages sit in the 2-byte row: é, ñ and ü all take two bytes, which is why a word like café is 4 characters but 5 bytes. Curly quotes, the em dash and the euro sign sit in the 3-byte row, and most emoji need four bytes.
UTF-8, UTF-16 and Windows-1252 bytes per character
| Character | Code point | UTF-8 | UTF-16 | Windows-1252 |
|---|---|---|---|---|
| A | U+0041 | 41 | 0041 | 41 |
| é | U+00E9 | C3 A9 | 00E9 | E9 |
| ñ | U+00F1 | C3 B1 | 00F1 | F1 |
| Ω | U+03A9 | CE A9 | 03A9 | not available |
| € | U+20AC | E2 82 AC | 20AC | 80 |
| “ | U+201C | E2 80 9C | 201C | 93 |
| — | U+2014 | E2 80 94 | 2014 | 97 |
| 日 | U+65E5 | E6 97 A5 | 65E5 | not available |
| あ | U+3042 | E3 81 82 | 3042 | not available |
| 😀 | U+1F600 | F0 9F 98 80 | D83D DE00 | not available |
| Ideographic space | U+3000 | E3 80 80 | 3000 | not available |
| Non-breaking space | U+00A0 | C2 A0 | 00A0 | A0 |
| BOM | U+FEFF | EF BB BF | FEFF | not available |
| ZWJ (joiner) | U+200D | E2 80 8D | 200D | not available |
Windows-1252 is a one-byte encoding, and its bytes 80 to 9F hold characters such as the euro sign (80), curly quotes (93 and 94) and the em dash (97). In the browser's own table the labels latin1 and iso-8859-1 are treated as windows-1252 too, which is why a page declared as "Latin-1" usually shows those characters correctly. Everything outside its 256 values, such as Ω, 日 or an emoji, simply cannot be stored in it.
The same text, a different number of bytes
| Text | Visible characters | Code points | UTF-8 | UTF-16 | Windows-1252 |
|---|---|---|---|---|---|
| Hello | 5 | 5 | 5 | 10 | 5 |
| café | 4 | 4 | 5 | 8 | 4 |
| “Hi” — 5 € | 10 | 10 | 18 | 20 | 10 |
| 日本語 | 3 | 3 | 9 | 6 | 日 not available |
| Hello 😀 | 7 | 7 | 10 | 16 | 😀 not available |
| 👨👩👧 (family) | 1 | 5 | 18 | 16 | not available |
For English letters UTF-8 is the shortest, while UTF-16 spends two bytes on every code unit, so plain English text doubles in size. The row “Hi” — 5 € shows the cost of typographic punctuation: ten characters become 18 bytes in UTF-8 because each curly quote, the dash and the euro sign takes three, while Windows-1252 still fits it in ten. That one-byte economy is why old files used it, and also why they break when the same bytes are read as UTF-8. The family emoji looks like one character on screen, but it is three person emoji (4 bytes each) joined by two ZWJ (3 bytes each), so it takes 18 bytes.
Five ways to write hex
| Format | Looks like | Typically used for |
|---|---|---|
| Space-separated | 63 61 66 C3 A9 | Hex viewers, writing bytes in documents and logs |
| Joined | 636166C3A9 | Output of Python bytes.hex(), hashes and keys written as one run |
| 0x array | 0x63, 0x61, 0x66, 0xC3, 0xA9 | Byte arrays in C, Java and JavaScript |
| \x escapes | \x63\x61\x66\xC3\xA9 | Python bytes display, C strings, MySQL error messages |
| % encoding | %63%61%66%C3%A9 | URLs |
When you paste, you do not have to choose a format. Spaces, tabs, line breaks, commas, colons and hyphens all count as separators, so the 63-61-66-C3-A9 that .NET's BitConverter.ToString prints goes in as it is. In the \x and % formats, plain letters and digits written between the escapes are read as bytes too, and a wrapper such as b'…', "…" or […] is stripped. RFC 3986 recommends uppercase hex in percent encoding, but upper and lower case are the same bytes.
// JavaScript: text → UTF-8 hex
[...new TextEncoder().encode('café')].map(b => b.toString(16).padStart(2, '0')).join(' '); // '63 61 66 c3 a9'
# Python 3.8 or later: text ↔ hex
'café'.encode('utf-8').hex(' ') # '63 61 66 c3 a9'
bytes.fromhex('63 61 66 C3 A9').decode('utf-8') # 'café' (spaces are ignored)
Bytes that are not valid UTF-8
Not every byte sequence is UTF-8. A continuation byte with no lead byte, a character cut off in the middle, or a character written longer than needed all make invalid UTF-8. RFC 3629 forbids encoding the surrogate range (U+D800 to DFFF) and warns decoders not to accept overlong forms such as C0 80. A browser puts one replacement character � (U+FFFD) for each invalid part; this converter splits the bytes by the same rule and marks the faulty bytes and the reason in the strip.
| Bytes | Why | Shown as |
|---|---|---|
80 | 10xxxxxx continues a character, but there is no lead byte | � |
FF | F5 to FF never occur in UTF-8 | � |
C0 80 | U+0000 stretched to two bytes, an overlong form (C0 and C1 are always forbidden) | �� |
E0 80 80 | after E0 only A0 to BF may follow (overlong) | ��� |
ED A0 80 | the surrogate U+D800 (after ED only 80 to 9F may follow) | ��� |
F4 90 80 80 | beyond U+10FFFF (after F4 only 80 to 8F may follow) | ���� |
E2 28 A1 | a 3-byte character cut after its first byte; 28 is read separately as "(" | �(� |
E2 82 | the euro sign € (E2 82 AC) is missing its last byte | � |
As in the last two rows, a character that is cut off is replaced as a whole: the bytes that were valid so far are grouped into a single �. Unicode calls this replacing the "maximal subpart", and the same bytes give the same number of � in a browser and in this converter. While you are typing in the hex box, a half-finished last character is not treated as an error; the converter tells you how many bytes it still needs, and judges it only once you leave the box.
Guessing the original encoding from garbled text
Most garbled text, called mojibake, comes from bytes saved in one encoding and read in another. The garbage has habits, so its shape tells you which way the mistake went.
| Original bytes | Misread as | Appears as |
|---|---|---|
UTF-8 'café' 63 61 66 C3 A9 | Windows-1252 | café |
UTF-8 'naïve' 6E 61 C3 AF 76 65 | Windows-1252 | naïve |
UTF-8 'café — 5 €' 63 61 66 C3 A9 20 E2 80 94 20 35 20 E2 82 AC | Windows-1252 | café — 5 € |
Windows-1252 '“café”' 93 63 61 66 E9 94 | UTF-8 | �caf� |
If an accented letter turns into à plus another symbol, and a dash, quote or euro sign turns into â followed by €, ‚ or similar, UTF-8 was read as Windows-1252. If curly quotes and accented letters turn into � instead, the text was probably Windows-1252 read as UTF-8, because a lone byte such as E9 or 93 is not valid UTF-8. Put the original bytes in the hex box and the converter tries UTF-8 first; when that fails, it prints the Windows-1252 reading underneath. The "Broken bytes" example, 93 63 61 66 E9 94, is the text “café” saved as Windows-1252.
Common mistakes
- Expecting a number base conversion: type 255 in the text box and you get 32 35 35, the bytes of the digit characters 2, 5 and 5, not FF. To change the base of a number use a base converter.
- Mixing code points with UTF-8 bytes: U+00E9 is the number of é, while C3 A9 is that number stored in UTF-8. If you put U+00E9 or \u00E9 in the hex box, you get a note that these are not bytes.
- Treating hex as encryption: hex is only a way of writing bytes, and anyone can turn it back into text. Do not use it to hide passwords or personal data.
- Not knowing whether to remove a leading EF BB BF: it is the UTF-8 byte order mark (U+FEFF), and at the start of a file it acts only as a signature. The Unicode FAQ says byte-oriented protocols that expect ASCII characters at the start should avoid it, and also says a protocol such as Microsoft's conventions for .txt files may require it. Check what the receiving program does before you keep or remove it.
- Expecting Windows line breaks 0D 0A: the browser's input boxes store a line break as LF (0A). A line break you type in the text box is 0A; to inspect a CR (0D), type 0D 0A into the hex box.
- Treating characters and bytes as the same count: where a length limit counts bytes, "Hello, café" costs 12 bytes for 11 characters, and emoji cost more. Read the three numbers above the strip together: characters, code points and bytes.
Limits
- Conversion happens only in your browser. The text and bytes you enter are not sent to a server and are not kept in the address or in storage.
- Text is converted up to 100,000 UTF-16 positions at a time and hex up to 1,200,000 positions, separators included. The strip draws only the first 1,500 characters and error bytes; the rest is still converted and copied.
- Hex output contains UTF-8 bytes only. UTF-16 and Windows-1252 appear only in the byte-count comparison and as per-character values in the bit lens.
- The Windows-1252 values follow the browser's WHATWG Encoding table, so an older program may differ on a few characters.
- The input is never normalized automatically. Decomposed (NFD) text only triggers a note, and it changes only when you press "Compose to NFC".
- Arbitrary binary files such as images or archives are out of scope. Use a Base64 tool to put a file into text.
- When reading % encoding, + stays a plus sign (2B), not a space. For form data, where + means a space, use a URL encoder/decoder.
Sources
Basis: UTF-8 rules come from RFC 3629 and chapter 3 of the Unicode Standard 18.0, browser encoding and decoding and the Windows-1252 table from the WHATWG Encoding Standard, and the other formats and messages from the documents below, all checked on 21 October 2026. The byte rules of UTF-8 have not changed since RFC 3629.
- 01RFC 3629 — UTF-8, a transformation format of ISO 10646U+0000 to 10FFFF as 1 to 4 bytes, surrogates forbidden, overlong C0 80 warning, BOM is EF BB BF
- 02The Unicode Standard 18.0 — Chapter 3, ConformanceTable 3-7 well-formed UTF-8 byte sequences, 3.9.6 U+FFFD replacement of a maximal subpart
- 03WHATWG — Encoding StandardUTF-8 decoder, TextDecoder fatal and ignoreBOM, the labels latin1 and iso-8859-1 resolve to windows-1252
- 04Unicode — UTF-8, UTF-16, UTF-32 & BOM FAQA BOM at the start is a signature; avoid it in byte-oriented protocols that expect ASCII, though some conventions require it
- 05RFC 3986 — URI Generic Syntax2.1 percent-encoding, uppercase hex recommended; 2.5 convert to UTF-8, then percent-encode
- 06MySQL 8.4 — The utf8mb3 Character SetAt most 3 bytes per character, BMP characters only (no supplementary characters), utf8 is a deprecated alias
- 07MySQL 8.4 — Server Error Message ReferenceError 1366 ER_TRUNCATED_WRONG_VALUE_FOR_FIELD: Incorrect %s value: '%s' for column
- 08Python 3 — Built-in Types: bytesbytes.fromhex ignores ASCII whitespace, bytes.hex(sep) since 3.8, bytes outside ASCII shown as \x escapes
- 09Microsoft Learn — BitConverter.ToStringHex pairs joined by hyphens, for example "7F-2C-4A-00"
- 10MDN — TextEncoderAlways encodes a JavaScript string as UTF-8
- 11MDN — String: lengthCounts UTF-16 code units, not characters
- 12Unicode Technical Standard #51 — Unicode EmojiRevision 31 (Emoji 18.0), emoji sequences joined with ZWJ
- 13Unicode Standard Annex #15 — Normalization FormsRevision 58, NFD = canonical decomposition, NFC = canonical decomposition followed by canonical composition
- 14Apple Technical Q&A QA1173 — Text Encodings in VFSHFS Plus (Mac OS Extended) uses a variant of Normal Form D for file names
Frequently asked questions
How many bytes is one character in UTF-8?
It depends on the character. ASCII letters such as A take 1 byte (41), accented letters such as é take 2 (C3 A9), characters such as € and curly quotes take 3 (E2 82 AC), and emoji take 4 (F0 9F 98 80). So café is 4 characters but 5 bytes.
How do I turn \xc3\xa9 or %C3%A9 into text?
Paste it into the hex box as it is. The converter reads \x escapes, % encoding, 0x prefixes and spaces, commas, colons or hyphens as separators, and also strips a wrapper such as b'...' and reads plain letters written between the escapes. The text box then shows é.
Are uppercase and lowercase hex different values?
No. C3 and c3 are the same byte (decimal 195). You can choose the output case, and RFC 3986 recommends uppercase for percent encoding in addresses.
What should I do when it says some bytes cannot be read as UTF-8?
Either a byte went missing or the text was saved in another encoding. The converter shows which byte is the first error and why, and if the bytes read cleanly as Windows-1252 it shows that reading underneath. For example, E9 alone is not valid UTF-8, but in Windows-1252 it is é.
Why does MySQL say Incorrect string value: '\xF0\x9F\x98\x80'?
F0 9F 98 80 are the four UTF-8 bytes of the emoji 😀. MySQL's utf8mb3 (formerly utf8) stores at most 3 bytes per character, so it cannot hold a 4-byte character. To store emoji, change the column's character set to utf8mb4, which uses up to 4 bytes.
Why does one emoji show up as 18 bytes?
A family emoji such as 👨👩👧 looks like one character, but it is three person emoji (4 bytes each) joined by two zero-width joiners, ZWJ (3 bytes each). That makes 5 code points and 18 bytes in UTF-8. The strip shows the ZWJ as its own label.
Why does café turn into café on some pages?
The page stored café as UTF-8 (63 61 66 C3 A9) but was read as Windows-1252, where C3 shows as à and A9 as ©. Put the original bytes into the hex box to confirm they are valid UTF-8, and then declare UTF-8 on the page or in the file.
Does entering 255 give FF?
No. This converter does not change the base of a number, it turns characters into UTF-8 bytes. The text 255 is the digit characters 2, 5 and 5, which gives 32 35 35. To turn the number 255 into hex FF, use a base converter.