Base64 encode/decode · Guide

Base64 Encode Browser: atob, btoa and the Unicode Problem

Browsers have shipped `btoa` and `atob` since the 1990s. They still work, they are still the fastest path — and they still break on any character outside Latin-1, which catches nearly everyone once.

The built-ins

btoa(s) encodes a binary string to Base64; atob(s) decodes back. The names come from "ASCII to binary" and the reverse, which is confusing in the opposite direction to what you would guess.

They operate on strings where each character represents one byte, values 0-255. That model is fine for binary data expressed that way and wrong for ordinary Unicode text.

The Unicode failure

btoa("café") throws InvalidCharacterError, because é is above U+00FF. Convert to UTF-8 bytes first and the problem disappears:

JavaScript
const toBase64 = (str) =>
  btoa(String.fromCharCode(...new TextEncoder().encode(str)));

const fromBase64 = (b64) =>
  new TextDecoder().decode(
    Uint8Array.from(atob(b64), (c) => c.charCodeAt(0))
  );

toBase64('café');    // 'Y2Fmw6k='
fromBase64('Y2Fmw6k=');  // 'café'

atob also throws on malformed input — bad padding, or - and _ from a base64url string. Wrap it in try/catch whenever the input comes from a user or an API.

Files and large data

For files, FileReader.readAsDataURL gives you a data URI with the Base64 already in it, handled natively and without stack limits:

JavaScript
const reader = new FileReader();
reader.onload = () => {
  const b64 = reader.result.split(',')[1];  // strip the data: prefix
};
reader.readAsDataURL(file);

Avoid String.fromCharCode(...bigArray) for large buffers — the spread exceeds the maximum argument count and throws. Chunk it, or use the FileReader route.

Frequently asked questions

Why does btoa throw InvalidCharacterError?

The string contains characters above U+00FF. Convert to UTF-8 bytes with TextEncoder first.

Are atob and btoa deprecated?

No. They are still standard and widely used; they simply predate Unicode-aware APIs.

How do I decode a JWT part in the browser?

Translate base64url to standard first: replace "-" with "+", "_" with "/", then pad to a multiple of 4.

Ready to try it?

Open the free browser-based Base64 encode/decode and apply what you just read — no sign-up, runs locally.

Open the Base64 encode/decode tool