Hex to Text
Decode hexadecimal byte sequences into readable UTF-8 text.
Hex to Text tool
What this tool does
Paste hexadecimal in whatever shape you found it and this turns it back into readable text. It
does not insist on a format: spaces, commas, colons, dashes, newlines, 0x
prefixes, \x escapes and one continuous run are all accepted, and the tool tells
you which shape it recognised.
The bytes are then decoded as UTF-8 by default. When that fails — because the data is Latin-1, UTF-16 or not text at all — it says so rather than producing a screen of question marks, and lets you switch interpretation or download the raw bytes.
Common uses
- Reading a packet capture or a serial log, where the payload is a run of bytes and only some of it is text.
-
Turning a Postgres
byteaor MySQLBINARYvalue back into the string that was stored. - Checking what an embedded device actually transmitted, byte by byte, against what the protocol document says.
- Decoding a value from a hex-encoded config file or a firmware dump.
-
Confirming whether a file starts with a known magic number —
89 50 4e 47is a PNG,25 50 44 46is a PDF.
A short example
These four inputs are identical as far as this tool is concerned:
48 65 6c 6c 6f
48656c6c6f
0x48, 0x65, 0x6C, 0x6C, 0x6F
48:65:6c:6c:6f All four decode to:
Hello When decoding goes wrong
Two failures account for most of them, and each has a specific fix:
- An odd number of digits. Every byte is exactly two digits, so an odd count
means one is missing — usually a dropped leading zero, where
0fwas written asf. - Bytes that are not valid UTF-8. A byte in the 0x80–0xFF range only makes sense as part of a multi-byte sequence. If those sequences are malformed, the data is probably Latin-1 (where every byte is its own character) or genuinely binary.
A strong hint sits in the stats above: a high proportion of printable ASCII means text, while
alternating zero bytes mean UTF-16 — 48 00 69 00 is "Hi" in little-endian UTF-16,
and decoding it as UTF-8 produces "H\0i\0".
Worth knowing
Hex is a view, not a format — it says nothing about what the bytes mean. The same
c3 a9 is "é" in UTF-8, "é" in Latin-1, and a fragment of a compressed stream in
a gzip file. Choosing the interpretation is your job, and the tool's analysis is a hint rather
than an answer.
One convenience worth knowing about: a leading # is stripped, so a CSS colour
like #ff8800 parses as the three bytes 255, 136, 0 — handy when checking a value
against an RGB triple.
Frequently asked questions
The hex from my C program looks byte-swapped. Why?
Because integers in memory are little-endian on x86 and ARM: the 32-bit value 0x0000002A sits in memory as 2a 00 00 00. This tool reads bytes left to right, the way a file or a captured packet is laid out, and protocol fields are big-endian — the order RFC 1700 calls network byte order. Reverse each multi-byte field before pasting, or you are reading the number backwards.
Why does my SHA-256 hash decode to gibberish?
Because a digest is not encoded text. Those 64 hex characters are 32 bytes engineered to look random, and reading them as UTF-8 can only produce noise — there is no input hidden inside, which is precisely the point of a hash. Compare instead of decoding: recompute the digest of the candidate string with the SHA-256 generator and check the two strings match.
Why does xxd -r give me something different?
xxd -r expects a full dump, offsets and ASCII gutter included, and treats the left-hand column as an address to seek to — hand it plain hex and it writes your bytes at wild offsets, padding the gaps with zeros. The flag you want is xxd -r -p, which reads a continuous run of hex digits, and xxd -p is what produces that form in the first place.