Text and byte hexadecimal encoding turns encoded data into a readable sequence of base-16 digits. For text, the process starts with a character encoding such as UTF-8. That encoding produces bytes, and hex then displays each byte as two digits. For example, Hi becomes 48 69.

This distinction matters whenever you inspect a file, debug an API response, or compare values in a log. Hex tells you which bytes exist. The character encoding tells you what those bytes mean as text. Mixing up those two jobs can turn a correct conversion into unreadable output.

Simple English letters make the process look straightforward because they each use one byte in UTF-8. Accented letters and emojis reveal the extra step. Once you understand that step, converting strings, reading byte arrays, and decoding hex back to text become much easier.

Quick Answer

To convert text to hex, encode the text as bytes using a character encoding such as UTF-8, then write each byte as two hexadecimal digits. To reverse the process, parse each hex pair into a byte and decode the resulting byte sequence using the original character encoding.

Why One Byte Uses Two Hex Digits

Hexadecimal, or base 16, uses the digits 0–9 and letters A–F. The letters represent decimal values 10 through 15. One hex digit holds four bits, often called a nibble. Two hex digits therefore hold eight bits, which make one byte, also called an octet.

A byte can hold a value from decimal 0 to 255. In hexadecimal, that range is 00–FF.

Consider the byte for an uppercase H in ASCII:

Representation

Value

Decimal

72

Binary

01001000

Hexadecimal

48

The two nibbles are 0100 and 1000, which become 4 and 8. Both formats describe the same byte value.

Base16, specified in RFC 4648, represents each input byte with two output characters and needs no padding. With no spaces or prefixes, the length follows this rule:

Hex character count = byte count × 2

A 20-byte value produces 40 hex characters. If stored as ASCII or UTF-8 text, those 40 characters occupy 40 bytes, before any separators are added.

Copper traces and a memory chip on a printed circuit board.
Keep the byte representation and its interpretation together. Original AI-generated editorial photograph.

Characters, Code Points, and Bytes Are Different

A character is part of the text you read. Unicode assigns code points to characters and other text elements. A code point is a number, commonly written with a U+ prefix, such as U+0041 for A.

A character encoding determines how those numbers become stored data. UTF-8 uses one to four bytes for each Unicode scalar value, meaning a valid code point other than a surrogate. A visible symbol can contain several code points, so it can require more than four bytes overall.

This is the key distinction in text and byte hexadecimal encoding: a Unicode code point and its UTF-8 bytes are different representations.

For example, é has the code point U+00E9, but its UTF-8 bytes are C3 A9. Writing E9 alone gives the Latin-1 encoding of that character, not its UTF-8 encoding.

ASCII covers 128 values. For characters in that set, UTF-8 preserves the same byte values. That is why an ASCII to hex example works identically when those same characters are encoded using UTF-8. Beyond ASCII, you must know which encoding produced the bytes.

How to Convert Text to Hex, Step by Step

Take the word Hello. To convert text to hex correctly, follow the operations in order:

  1. Choose the character encoding. Here, use UTF-8.
  2. Encode the text into bytes.
  3. Convert each byte value to hexadecimal.
  4. Keep exactly two digits for every byte.
  5. Add separators only if the receiving tool accepts them.

The resulting values are:

Character

Decimal Byte Value

Hex Byte

H

72

48

e

101

65

l

108

6C

l

108

6C

o

111

6F

The output is 48 65 6C 6C 6F, or 48656C6C6F without spaces.

To calculate one byte manually, divide its decimal value by 16. The quotient gives the first hex digit, and the remainder gives the second. For H, 72 divided by 16 gives 4 with a remainder of 8, producing 48.

Once you already have binary data, skip the text-encoding step. A byte array containing decimal values [0, 15, 255] becomes 000fff. There is no need to interpret those bytes as characters first.

Grid-paper notebook, pencil, keyboard and USB cable on a desk.
Work through a small example and verify the result. Original AI-generated editorial photograph.

UTF-8 Examples: Letters, Symbols, and Emojis

A string to hex conversion should show the bytes of the chosen encoding, not simply print every code point in base 16.

Text

Unicode Code Point

UTF-8 Hex

Byte Count

A

U+0041

41

1

Space

U+0020

20

1

é

U+00E9

C3 A9

2

€

U+20AC

E2 82 AC

3

😀

U+1F600

F0 9F 98 80

4

Now consider Aé😀. It contains three code points but occupies seven UTF-8 bytes:

41 C3 A9 F0 9F 98 80

Its continuous hex representation has 14 digits. Counting the visible symbols and multiplying by two would give the wrong result.

The bytes can also change with the encoding. For A, UTF-8 produces 41, UTF-16 little-endian produces 41 00, and UTF-16 big-endian produces 00 41, excluding any byte order mark. Choose the encoding before calculating the expected hex output.

Convert Strings and Bytes to Hex in Python

Python keeps text strings and bytes as separate types. Use str.encode() to create bytes, then bytes.hex() to produce hexadecimal text.

text = "Café"
raw = text.encode("utf-8")
hex_text = raw.hex()
print(hex_text)       # 436166c3a9
print(raw.hex(" "))   # 43 61 66 c3 a9
print(len(raw))       # 5

The result contains five bytes even though the text has four code points. The final letter uses two UTF-8 bytes.

For existing bytes, call .hex() directly:

raw = bytes([0, 15, 255])
print(raw.hex())  # 000fff

Leading zeros are preserved automatically. Avoid converting the entire byte sequence to an integer just to format it as hex, because that can discard its original width.

To convert a hex string back to bytes and then text:

hex_text = "43 61 66 c3 a9"
raw = bytes.fromhex(hex_text)
text = raw.decode("utf-8")
print(text)  # Café

bytes.fromhex() accepts ASCII whitespace between byte pairs. It raises ValueError for malformed input, including incomplete pairs. Valid hex can still produce bytes that fail UTF-8 decoding, which raises UnicodeDecodeError. Handle these as separate failures: one concerns the hex format, while the other concerns the text encoding.

Convert Text to Hex in JavaScript and Node.js

Browser JavaScript and Node.js offer different APIs. Both can produce the same UTF-8 bytes when used correctly.

Hands typing on a computer keyboard beside a softly blurred screen.
Test a known example before converting a larger input. Original AI-generated editorial photograph.

Browser JavaScript with TextEncoder

TextEncoder converts a JavaScript string to a Uint8Array of UTF-8 bytes. Format each array element as a two-digit hex value:

function textToHex(text) {
  const bytes = new TextEncoder().encode(text);
  return Array.from(bytes, byte =>
    byte.toString(16).padStart(2, "0")
  ).join("");
}
console.log(textToHex("Café")); // 436166c3a9

The padStart() call matters. Decimal 5 becomes 05, preserving a full byte pair. This same formatting step converts any byte array to hex string output.

Do not use charCodeAt() as a general replacement for UTF-8 encoding. JavaScript strings contain UTF-16 code units, and those units are not the UTF-8 bytes needed here.

For decoding, validate the input, build the byte array, and use TextDecoder:

function hexToText(input) {
  const hex = input.replace(/\s+/g, "");
  if (hex.length % 2 !== 0 || /[^0-9a-f]/i.test(hex)) {
    throw new Error("Expected complete hexadecimal byte pairs");
  }
  const bytes = Uint8Array.from(
    hex.match(/.{2}/g) ?? [],
    pair => parseInt(pair, 16)
  );
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}
console.log(hexToText("43 61 66 c3 a9")); // Café

This function accepts whitespace but rejects prefixes and punctuation. The fatal option makes invalid UTF-8 fail rather than quietly inserting replacement characters.

Node.js with Buffer

For Node.js, use a Buffer to move between strings and bytes:

const hex = Buffer.from("Café", "utf8").toString("hex");
console.log(hex); // 436166c3a9
const text = Buffer.from(hex, "hex").toString("utf8");
console.log(text); // Café

Validate untrusted hex input before calling Buffer.from(). Node.js can truncate hex input at an invalid character or incomplete pair. Also, .toString("utf8") can replace invalid UTF-8 sequences rather than reject them. Use a strict TextDecoder when malformed text must trigger an error.

Why Hex Decoding Sometimes Produces the Wrong Text

Converting a hex string to bytes and decoding those bytes as text are separate checks. A value can pass the first check and fail the second.

For instance, FF is valid hex and describes one byte. That byte alone is not valid UTF-8 text. An image, compressed file, or encrypted payload can contain many such values without anything being wrong with the underlying data.

Other problems come from assumptions about format or encoding:

Symptom

Likely Cause

What to Check

Accented text becomes é

UTF-8 bytes interpreted using a different encoding

Confirm the source encoding

Unexpected replacement character �

Invalid or incomplete encoded text

Inspect the original byte sequence

Odd-length hex string

A digit was lost or input uses another format

Recover complete byte pairs

Invisible differences in strings

Spaces, line endings, or control characters

Compare the hex dump

Parser rejects 0x48

Prefix not supported

Follow that parser's input rules

A newline is a useful debugging example. LF appears as 0A, while CRLF appears as 0D 0A. Two lines can look identical in an editor yet contain different bytes.

Keep raw input during troubleshooting. Silently removing every non-hex character can conceal corruption and produce a different byte sequence that looks valid.

Formatting, Base64, and Practical Limits

Uppercase and lowercase hex have the same numeric meaning. c3a9 and C3A9 describe identical bytes. Spaces, commas, 0x prefixes, and \x escapes are formatting conventions whose acceptance depends on the receiving parser.

For example, 48, 0x48, and \x48 can all describe the byte value 72 in appropriate contexts. They are not interchangeable input strings for every decoder.

The hex encoding vs Base64 size difference matters when sending binary data through text-based systems. Hex produces two characters per byte. Standard padded Base64 produces four characters for each group of up to three bytes.

For 12 input bytes, hex uses 24 characters and Base64 uses 16. Hex is convenient when you need to inspect individual bytes; Base64 is more compact. Neither representation encrypts the data or provides confidentiality.

Use text to hex encoding when you need readable byte values for debugging, test fixtures, or byte-by-byte comparisons. If your goal is smaller text output, consider Base64. If your goal is secrecy, choose an appropriate encryption system instead.

For a practical comparison, imagine an API expects the text 10. Encoding that string as UTF-8 gives 31 30, because it contains the characters 1 and 0. Formatting the integer 10 as hexadecimal gives 0A when padded to a byte. Those outputs differ because the inputs have different meanings.

Make that distinction explicit in test fixtures and API documentation. State whether a field contains text, a number, or raw binary data, then specify the encoding and separators. A sample input with its expected output helps another developer reproduce your result without guessing what the field represents.

Frequently Asked Questions

Is hexadecimal a character encoding?

Hexadecimal describes numeric values using base 16. Base16 encoding represents bytes as hexadecimal characters. A character encoding such as UTF-8 performs a different job: it maps text to encoded data. Calling both operations “encoding” is common, but they happen at different stages when text becomes hex.

How do I know which encoding a hex string uses?

A hex string alone usually cannot identify its original text encoding. Check the file format, protocol, application settings, or documentation that produced it. A byte order mark can provide a clue in some formats, but many byte sequences have no encoding marker and can fit several possible interpretations.

Does converting text to hex change the original information?

Converting a byte sequence to hex preserves every byte when all pairs are retained. Recovering the original text also requires the correct character encoding. Editing the bytes, dropping leading zeros, replacing invalid characters, or applying Unicode normalization can change what comes back. Hex conversion itself does not require those changes.

Why can identical-looking text have different hex values?

Unicode can represent some visible text in more than one way. For example, é can be one precomposed code point or an e followed by a combining accent. Their UTF-8 byte sequences differ. Normalize text only when your application needs equivalent text forms treated consistently; do not silently normalize byte-sensitive data.

Do I need to reverse bytes when decoding hex?

No. Ordinary hex-to-text conversion preserves the byte sequence in its given order. Byte order matters when a format defines multibyte values, such as UTF-16 code units or integers. Reverse bytes only when that specific format requires it, not simply because the input happens to be hexadecimal.

Can I use an online text-to-hex converter?

Yes, provided it supports the required character encoding and output format. Check a known input such as é, whose UTF-8 hex is C3 A9. For private data, confirm how the tool processes and stores input. Do not assume every converter runs locally just because it appears in a browser.

Is hex the same as URL percent-encoding?

No. URL percent-encoding represents selected bytes as a percent sign followed by two hex digits, such as %20 for a space. Its rules depend on the URL component being encoded. A raw hex string has no percent signs and does not follow those component-specific escaping rules by itself.

Keep the Encoding with the Data

Reliable text and byte hexadecimal encoding depends on preserving two things: the full byte sequence and the character encoding used to create it. Choose UTF-8 for these examples, retain two digits per byte, and check the decoded output against the original input. When something looks wrong, inspect the bytes before changing the text.