Hex to Text
Turn a hex dump back into words — spaced or unspaced, decoded as UTF-8, with bytes that are not text marked rather than guessed at.
Runs 100% in your browser•Nothing is uploaded to a server•Free forever
Hexadecimal
Text
Reading a hex dump back into words
Every two hex digits are one byte, and the bytes are decoded as UTF-8. Paste with spaces, without them, with a 0x in front, or straight out of a dump with its offsets stripped — the converter chunks unseparated input into byte-sized pairs from the right, so an odd number of digits leaves only the leading nibble short instead of shifting the whole run.
This is the everyday way to find out what a blob in a log, a packet capture or a database column actually says, and it is usually faster than reaching for a script.
The first byte tells you how long the character is
UTF-8 is self-describing, which is what makes decoding possible without any extra information. The value of a byte says whether it starts a character and how many bytes that character occupies:
| First byte | Bytes in the character | What lives there |
|---|---|---|
00–7F | 1 | plain ASCII — the byte is the character |
80–BF | — | a continuation byte; never valid on its own |
C2–DF | 2 | Latin-1 supplement, Greek, Cyrillic, Hebrew, Arabic |
E0–EF | 3 | most of the rest of the Basic Multilingual Plane, CJK included |
F0–F4 | 4 | emoji, historic scripts, everything above U+FFFF |
C0, C1, F5–FF | — | never valid anywhere in UTF-8 |
That structure is why UTF-8 can be resynchronised: land in the middle of a stream, skip forward until you see a byte outside 80–BF, and you are at a character boundary again. It is also why a truncated run fails loudly rather than silently producing the wrong character.
| Hex | Bytes | Decodes to |
|---|---|---|
48 | 1 | H |
69 | 1 | i |
21 | 1 | ! |
0A | 1 |
|
C3A9 | 2 | é |
E282AC | 3 | € |
F09F9087 | 4 | 🐇 |
When it does not decode
A � in the output is the standard replacement character, emitted once for every byte that cannot begin or continue a valid sequence. A few of them usually means the run was cut mid-character or a byte was mistyped. A page of them means the data is not UTF-8 text — it may be an image, a compressed archive, an encrypted payload, or text in a legacy encoding such as Latin-1 or Shift-JIS, none of which this page can decode.
Bytes above 127 that decode to unexpected accented characters are the classic sign of the opposite mistake: Latin-1 data being read as UTF-8, or the reverse.
Some hex is not text on purpose
Hash digests, keys, UUIDs and binary file headers are hex because they are numbers or raw bytes, not because they encode a string. Trying to decode a SHA-256 digest as text will always produce nonsense; if the hex is a hash, compare it as a hash with the hash generator instead. If it is a number, hex to decimal is the page you want.
Related: text to hex for the return trip, binary to text for the same job from bits, and the number base converter.
More developer tools
- JSON Formatter
- Base64 Encode / Decode
- URL Encoder / Decoder
- Unix Timestamp Converter
- Regex Tester
- UUID Generator (v4 / v7)
- Hash Generator (MD5 / SHA / HMAC)
- JWT Decoder
- Password Generator
- JSON ⇄ CSV Converter
- HTML Entity Encoder / Decoder
- Cron Expression Explainer
- Color Converter
- WCAG Contrast Checker
- All tools on one page (home)