
Last checked by the TextEditor.com team
Encoding is not encryption
Encoding writes the same text with other characters, so it can travel where some characters are not allowed. A web address can't hold a space. An email once could hold only ASCII. Anyone can decode it again, with no key or password. Base64 hides nothing. To keep a secret, you need encryption, and a strong password to go with it.
| Format | Result | Used for |
|---|---|---|
| Base64 | Q2Fmw6kg8J+YgA== | Email attachments, data URLs, tokens |
| Base64URL | Q2Fmw6kg8J-YgA | Web addresses and JSON Web Tokens |
| URL encoding | Caf%C3%A9%20%F0%9F%98%80 | Values in a web address |
| Form data | Caf%C3%A9+%F0%9F%98%80 | What a web form sends |
| HTML entities | Café 😀 | Text inside a web page |
| JavaScript escapes | Caf\u00E9 \uD83D\uDE00 | Strings in code and JSON |
| Hex bytes | 43 61 66 C3 A9 20 F0 9F 98 80 | Debugging, network tools |
| Quoted-printable | Caf=C3=A9 =F0=9F=98=80 | Email text |
| ROT13 | Pnsé 😀 | Hiding spoilers and puzzle answers |
How UTF-8 turns letters into bytes
Computers store bytes, numbers from 0 to 255. Base64, URL encoding, hex, binary and quoted-printable start by turning your text into bytes with UTF-8, the encoding used by almost every web page. Each character has a number in Unicode, its code point. UTF-8 writes that number in 1 to 4 bytes.
The first bits of each byte say how it is used. A byte that starts with 0 is a whole character from ASCII. A byte that starts with 110, 1110 or 11110 starts a character of 2, 3 or 4 bytes. Every byte that starts with 10 continues one. The rest of the bits, in black below, are the code point in binary.
| Character | Code point | Bytes | Bits (marker bits in color) | Hex |
|---|---|---|---|---|
| H | U+0048 | 1 | 01001000 | 48 |
| é | U+00E9 | 2 | 1100001110101001 | C3 A9 |
| € | U+20AC | 3 | 111000101000001010101100 | E2 82 AC |
| 😀 | U+1F600 | 4 | 11110000100111111001100010000000 | F0 9F 98 80 |
4 characters, 10 bytes. In UTF-16, the way JavaScript counts, the same text is 5 units long.
| Code points | Bytes | Bit pattern | Examples |
|---|---|---|---|
| U+0000 to U+007F | 1 | 0xxxxxxx | A to Z, digits, signs |
| U+0080 to U+07FF | 2 | 110xxxxx 10xxxxxx | é, ß, Greek, Cyrillic, Hebrew, Arabic |
| U+0800 to U+FFFF | 3 | 1110xxxx 10xxxxxx 10xxxxxx | €, Chinese, Japanese, Korean, most symbols |
| U+10000 to U+10FFFF | 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | Emoji, rare scripts, math letters |
That is why "Read bytes as" matters when you decode. The same bytes read as Windows-1252 turn é into é. If you see text like that, the bytes were right, but they were read with the wrong character set.
How Base64 works
Base64 takes 3 bytes at a time. That is 24 bits, which it cuts into four groups of 6 bits. Each group is a number from 0 to 63, and each number has a character: A to Z, a to z, 0 to 9, + and /. So 3 bytes become 4 characters, and the result is about a third longer. When the last group has only 1 or 2 bytes, = signs fill the gap.
Bytes01001000 11000011 10101001
6 bit groups010010 001100 001110 101001
Numbers18 12 14 41
Base64SMOp
The rules are in RFC 4648. It also defines Base64URL, which uses - and _ instead of + and /, because those two have a meaning in web addresses. JSON Web Tokens use Base64URL without the = at the end.
In JavaScript, the old btoa() function reads each character as one byte. It turns é into "6Q==", which is not UTF-8, and it fails on € and every emoji. This tool encodes the text as UTF-8 first, so every character comes back the same after decoding.
URL encoding: encodeURIComponent, encodeURI and form data
A web address uses some characters to mark its parts. The ? starts the query, & splits values, # starts the fragment. To put one of them inside a value, write it as % and two hex digits. A character outside ASCII becomes its UTF-8 bytes, so é becomes %C3%A9.
JavaScript has two functions for it. Use encodeURIComponent for one value, like a search word. Use encodeURI for a whole address you already built, because it keeps the characters that give it shape. Web forms send data a third way: a space becomes +. Email and SMS QR codes use the same percent encoding. The QR code generator adds it for you.
| Character | encodeURIComponent | encodeURI | Form data |
|---|---|---|---|
| Space | %20 | %20 | + |
| & | %26 | & | %26 |
| = | %3D | = | %3D |
| ? | %3F | ? | %3F |
| / | %2F | / | %2F |
| # | %23 | # | %23 |
| + | %2B | + | %2B |
| é | %C3%A9 | %C3%A9 | %C3%A9 |
| ~ | ~ | ~ | %7E |
| ! | ! | ! | %21 |
| ' | ' | ' | %27 |
Shaded cells stay as they are. Form data here follows URLSearchParams in your browser.
When you decode form data, turn on the form mode, or every + stays a plus sign. A % that is not followed by two hex digits is an error. The tool shows where it is.
HTML entities: named or numeric?
In HTML, five characters can break a page: &, <, > and the two quote marks. Write them as &, <, >, " and ', and the browser shows them as text instead of reading them as code. This is also the first step against code injection in web forms.
Other characters need no entity on a page saved as UTF-8. Entities still help when you can't type a character or want to see it in the source, like for a no-break space. HTML has 2,125 named entities. A numeric one, like é or é, works for every character, even those with no name.
Unicode escapes in code
Program code is often kept in ASCII, so other characters go in as escapes. Each language has its own form. JavaScript and JSON need two escapes for an emoji, because they count text in UTF-16 units.
| JavaScript, JSON, Java, C# | \uD83D\uDE00 |
|---|---|
| Modern JavaScript | \u{1F600} |
| Python, C, C++ | \U0001F600 |
| CSS | \1F600 |
| HTML | 😀 |
| Code point | U+1F600 |
In CSS, an escape ends at the first character that is not a hex digit. If a digit or a letter from A to F comes next, put a space after the escape. The space is eaten by the escape and does not show. To look up any character by name, use the character list.
Hex, binary, ROT13, quoted-printable and Punycode
Hex and binary show the UTF-8 bytes as numbers. Hex writes each byte as two digits from 0 to F. Binary writes eight 0s and 1s. Programmers use hex to see what a file really holds. The ASCII table lists the first 128 values in all three forms. To see each letter over its own bits, or to read binary with missing spaces or zeros, use the binary translator.
ROT13 moves each letter 13 places in the alphabet. Doing it twice gives back the text, so the same button encodes and decodes. It hides spoilers from a quick glance, and nothing more. ROT47 does the same with digits and signs.
Quoted-printable is the email format for text that is mostly ASCII. Plain letters stay, and other bytes become = and two hex digits. Lines are kept to 76 characters or fewer, and an = at the end of a line means it goes on. If an email shows =C3=A9 instead of é, paste it here and pick Quoted-printable.
Punycode writes domain names with other letters in ASCII. The name münchen.de becomes xn--mnchen-3ya.de, which is what your browser looks up. It also helps you spot fakes. The address аpple.com with a Cyrillic а becomes xn--pple-43d.com, which shows at once that it is not the real one.
Which encoding do I have?
The tool guesses for you when you paste. These are the clues it looks for.
| You see | It is probably |
|---|---|
| SGVsbG8gd29ybGQ= | Base64: letters, digits, + and /, length a multiple of 4, maybe = at the end |
| eyJhbGciOi... | A JSON Web Token: three Base64URL parts split by dots, the first starting with eyJ |
| Hello%20world%21 | URL encoding: % and two hex digits |
| <b> é | HTML entities: & and a name or a number, then ; |
| \u00E9 \x41 | Unicode escapes from code |
| 48 65 6C 6C 6F | Hex bytes: pairs of 0 to 9 and A to F |
| Caf=C3=A9 | Quoted-printable: = and two hex digits, = at line ends |
| xn--mnchen-3ya | Punycode: a domain part that starts with xn-- |
Hidden characters can also break decoding. A zero width space inside Base64 is not one of its 64 characters, so it gives an error. The invisible character finder shows them and takes them out.