Skip to content
FindTool

    Hex to Text

    Decode hexadecimal byte sequences into readable UTF-8 text.

    Hex to Text tool

    Going the other way? Use Text to Hex.

    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 bytea or MySQL BINARY value 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 47 is a PNG, 25 50 44 46 is 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 0f was written as f.
    • 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.