CalcOpenly
English

Base64, URL and HTML encoder and decoder

Encode or decode Base64, URL-safe Base64, URL percent-encoding, HTML entities, hex bytes and Unicode code points, with UTF-8 and UTF-16 byte counts.

Drafted with AI writing toolsUpdated Checked examples: 17

Try
Result
Q2Fmw6kgJiBjcsOobWUsIDUg4oKs
Result: Q2Fmw6kgJiBjcsOobWUsIDUg4oKs
Characters (code points)
17
UTF-8 bytes
21
UTF-16 code units
17
Result length
28characters

17 characters become 21 UTF-8 bytes; as Base64 they take 28 characters, 1.33 per byte.

Sizes

Characters17UTF-8 bytes21UTF-16 bytes34Base64 output28

UTF-8 bits of the first characters

“C” U+0043 → 43
0
1
0
0
0
0
1
1
“a” U+0061 → 61
0
1
1
0
0
0
0
1
“f” U+0066 → 66
0
1
1
0
0
1
1
0
“é” U+00E9 → c3 a9
1
1
0
0
0
0
1
1
1
0
1
0
1
0
0
1
How it's calculated S
  1. Encode the text as UTF-8

    17 characters → 21 bytes.

  2. Regroup 8-bit bytes into 6-bit indices

    First group: 43 61 66 → 010000 110110 000101 100110 → 16, 54, 5, 38 → “Q2Fm”.

  3. Output length

    4⌈213⌉=284 \left\lceil \frac{21}{3} \right\rceil = 28

About the base64, URL and HTML encoder and decoder

Every scheme here starts from the text's UTF-8 bytes. Base64 regroups each 3 bytes into four 6-bit values drawn from a 64-character alphabet (RFC 4648), so the output is 4 × ⌈n ÷ 3⌉ characters. Percent-encoding writes every byte outside A–Z, a–z, 0–9 and - . _ ~ as %XX (RFC 3986), HTML escaping replaces & < > " and ' with character references, and hex writes two digits per byte.

Developers use it to put binary data in JSON or email, build query strings, read JWTs and track down character-set problems. The default, "Café & crème, 5 €", is 17 characters but 21 UTF-8 bytes, because é and è take 2 bytes each and € takes 3, and its Base64 form is 28 characters.

A decoding error names the bad character and its position, and bytes that aren't valid UTF-8 show as U+FFFD (�).

How Base64 encoding works

Base64 writes bytes as plain text. It takes the text's UTF-8 bytes three at a time, splits each 24-bit group into four 6-bit values and maps each value to one of 64 characters: A–Z, a–z, 0–9, + and /. So Man becomes TWFu, and every 3 bytes become 4 characters, which makes the output about 33% larger.

Encoding Man by hand

  1. Take the bytes: M = 0x4D, a = 0x61, n = 0x6E.
  2. Write them as 24 bits: 01001101 01100001 01101110.
  3. Regroup into 6-bit values: 010011 010110 000101 101110 = 19, 22, 5, 46.
  4. Look each value up: 0–25 are A–Z, 26–51 are a–z, 52–61 are 0–9, then + and /. So 19 = T, 22 = W, 5 = F and 46 = u.

When the length is not a multiple of 3, the last group is filled with zero bits and = signs: Ma is TWE= and M is TQ==. RFC 4648 defines the alphabet and the padding rules.

Base64 versus Base64URL

The URL-safe alphabet swaps + and /, which clash with URLs and file names, for - and _, and usually drops the padding. <<???>> is PDw/Pz8+Pg== in standard Base64 and PDw_Pz8-Pg in Base64URL.

Signed JSON Web Tokens use Base64URL for each of their three dot-separated parts. Their headers usually start with eyJ, the encoding of {" followed by a letter: eyJhbGciOiJIUzI1NiJ9 decodes to {"alg":"HS256"}.

Percent-encoding for URLs

RFC 3986 leaves only letters, digits and - . _ ~ as they are. Every other byte becomes % plus two hex digits, and non-ASCII characters are encoded from their UTF-8 bytes, so é becomes %C3%A9.

The query value a b&c=d/é? becomes a%20b%26c%3Dd%2F%C3%A9%3F. The &, = and / are escaped because they belong to the value, so encode each URL component on its own, never a whole URL.

  • Space as %20 or +. HTML forms (application/x-www-form-urlencoded) write a space as +, so a+b in a form query means a b. In a URL path, + is a literal plus.
  • JavaScript. encodeURIComponent gives the same result except that it leaves ! ' ( ) * unescaped. encodeURI keeps / ? & = # intact and suits whole URLs only.
  • Double encoding. Encoding %20 again gives %2520. Decode once, where the value enters your code.

HTML entities, hex bytes and code points

HTML escaping replaces the five characters that can break markup: & with &amp;, < with &lt;, > with &gt;, " with &quot; and ' with &#x27;. That protects text inside elements and quoted attributes, not inside a <script> block or a URL.

Hex writes each UTF-8 byte as two digits, so é€ is c3 a9 e2 82 ac. Code-point notation names characters instead of bytes: A€😀 is U+0041 U+20AC U+1F600.

Characters, bytes and UTF-16 units

A code point takes 1 to 4 bytes in UTF-8 (RFC 3629) and 1 or 2 code units in UTF-16. JavaScript strings count UTF-16 units, so "😀".length is 2.

ScenarioCode pointsUTF-8 bytesUTF-16 units
Default172117
unicode Unicode384
Combining marks232
Emoji sequence72511
Invalid UTF-8 hex222

Default is Café & crème, 5 €, where é and è take 2 bytes each and € takes 3. The second row is A€😀, and the third is an e followed by the combining accent U+0301.

The emoji row is the family 👨‍👩‍👧‍👦: four people joined by three zero-width joiners, drawn as one symbol. The last row decodes the hex bytes c3 28, which are invalid UTF-8 and come out as �(.

Common encoding mistakes

  • Treating Base64 as encryption. It has no key, and anyone can decode it in one step.
  • Calling btoa on Unicode text. In browsers btoa('é') returns 6Q==, the Latin-1 byte, not the UTF-8 w6k=, and btoa('€') throws. Encode to UTF-8 bytes first, for example with TextEncoder.
  • Mixing the two Base64 alphabets. A strict standard decoder rejects - and _, and a strict Base64URL decoder rejects + and /.
  • Counting characters as bytes. Café & crème, 5 € is 17 characters but 21 UTF-8 bytes, which matters for column limits and Content-Length headers.

What the decoders accept

  • Base64 and hex decoding ignore whitespace and line breaks, and unpadded Base64 is accepted.
  • Hex accepts spaces, colons and 0x prefixes. Code points can be written U+1F600, \u{1F600}, 0x1F600 or &#x1F600;.
  • Bytes that are not valid UTF-8 decode to U+FFFD (�), with a warning that gives the position.
  • Text you enter is written into the page address and its on-device history, so never paste live tokens or keys.

To fingerprint data instead of encoding it, use the hash calculator.

Worked examples

Base64 of “foob” (two padding characters)

Encoding
Base64
Direction
Encode
Text
foob
Result
Zm9vYg==
UTF-8 bytes
4
Result length
8 characters

Checked against: RFC 4648 §10 test vectors

Base64 of an empty string

Encoding
Base64
Direction
Encode
Result
UTF-8 bytes
0
Result length
0 characters

Checked against: Independent calculation

URL-safe Base64 without padding

Encoding
Base64 (URL-safe)
Direction
Encode
Text
<<???>>
Result
PDw_Pz8-Pg
Result length
10 characters

Checked against: the standard alphabet gives PDw/Pz8+Pg==

Decode Base64 to Chinese text

Encoding
Base64
Direction
Decode
Encoded text
5L2g5aW9IOS4lueVjA==
Result
你好 世界
Characters (code points)
5
UTF-8 bytes
13
UTF-16 code units
5

Checked against: Independent calculation

Questions

Why does Base64 make data about 33% larger?

Base64 carries 6 bits in each output character against 8 bits in each input byte, so every 3 bytes become 4 characters, a ratio of 4 to 3, plus up to 2 = padding characters at the end. 21 bytes become 28 characters, and 1 MB of binary becomes about 1.33 MB. MIME email (RFC 2045) also breaks the output into lines of at most 76 characters, which adds a little more.

What is the difference between Base64 and Base64URL?

Base64URL (RFC 4648 §5) replaces the two characters that clash with URLs and file names, + and /, with - and _, and usually drops the = padding. JSON Web Tokens (RFC 7519) use it for all three of their parts. The text <<???>> is PDw/Pz8+Pg== in standard Base64 and PDw_Pz8-Pg in the URL-safe form, 10 characters instead of 12.

Is Base64 a form of encryption?

No. Base64 is a reversible encoding with no key, so anyone can decode it in one step; it only makes binary data safe to carry as text. HTTP Basic authentication (RFC 7617), for example, sends user:password in Base64, which is why it is only safe over HTTPS. To protect data, encrypt it first, for example with AES-256, and then Base64-encode the ciphertext if it must travel as text.

Should a space be URL-encoded as %20 or +?

Both appear, in different places. RFC 3986, which governs URLs, encodes a space as %20, while HTML form submissions (application/x-www-form-urlencoded) write it as +. So a+b in a form's query string means a b, but in a URL path the + is a literal plus. JavaScript's encodeURIComponent gives %20, and Python's urllib.parse.quote_plus gives +.

How many bytes does a character take in UTF-8?

One to four. Code points below U+0080 (ASCII) take 1 byte, those up to U+07FF take 2 (é, ñ, Greek, Cyrillic), those up to U+FFFF take 3 (€ and most Chinese characters) and the rest take 4, including emoji such as 😀 (U+1F600). So A€😀 is 3 characters, 8 UTF-8 bytes and 4 UTF-16 code units, because 😀 needs a surrogate pair in UTF-16 (RFC 3629).

About this calculator

Base64 length=4⌈n3⌉hex length=2nn=UTF-8 bytes\begin{aligned} \text{Base64 length} &= 4\left\lceil \frac{n}{3} \right\rceil \\ \text{hex length} &= 2n \\ n &= \text{UTF-8 bytes} \end{aligned}

Sources

  1. RFC 4648 — The Base16, Base32, and Base64 Data Encodings
  2. RFC 3986 §2 — URI characters and percent-encoding
  3. RFC 3629 — UTF-8, a transformation format of ISO 10646
  4. WHATWG HTML — Named character references
  5. The Unicode Standard, §3.9 Unicode encoding forms

Checked against references

This calculator includes 17 worked examples with independently sourced answers. They run in the test suite, and you can run them here too.

Put this calculator on your site

Paste this where you want the calculator to appear. It is free to use, it stays in step with corrections made here, and the credit line below it links back so your readers can find the full version.

Height
Preview the embed

Keep the credit line. It is the only condition, and it is what keeps these calculators free.