Base64 Encoder and Decoder

Converts as you type, handles every character UTF-8 can express, and never leaves your browser.

Direction

Base64 is encoding, not encryption

Worth stating plainly because it is the most common misunderstanding: Base64 hides nothing. It is a reversible mapping from arbitrary bytes onto 64 printable characters, designed so binary data survives channels that only tolerate text — email bodies, JSON strings, data URIs, HTTP headers, XML attributes. Anyone can decode it in a second, as this page demonstrates. If a value needs to stay secret, it needs encryption; Base64 on top of that is just transport.

The cost of that safety is size. Three bytes become four characters, so output is about 33% larger than input, plus padding. That matters when you inline a large image as a data URI and wonder why the page grew.

Why btoa throws on your string

If you have hit InvalidCharacterError in the browser console, this is why: btoa predates JavaScript's Unicode handling and accepts only characters in the Latin-1 range, 0–255. Give it "café" and it manages; give it "日本語" and it throws. Give it something in between and you can get silently mangled output, which is worse.

The fix is to convert the text to UTF-8 bytes first and Base64 those bytes:

// Encode any string safely
const b64 = btoa(String.fromCharCode(...new TextEncoder().encode(text)));

// Decode back
const text = new TextDecoder().decode(
  Uint8Array.from(atob(b64), c => c.charCodeAt(0))
);

That spread operator will blow the argument limit on large inputs, so this page chunks the conversion in 32 KB blocks instead. This tool does the UTF-8 step for you in both directions, which is why emoji and CJK text round-trip here without special handling.

The URL-safe alphabet

Standard Base64 uses + and /, both of which have meaning in URLs, and = for padding, which has meaning in query strings. RFC 4648 defines a variant substituting - and _ and usually dropping the padding. That is what JSON Web Tokens use, which is why a JWT segment often looks like Base64 but fails a strict decoder.

This decoder accepts both alphabets and restores missing padding automatically, so you can paste a raw JWT segment or a value lifted from a URL without cleaning it up first. Tick URL-safe alphabet to produce that form when encoding.

Padding, and why length matters

Base64 works in blocks of three bytes. When the input does not divide evenly, the output is padded with one or two = characters so its length is always a multiple of four. A string whose length leaves a remainder of one is therefore impossible — no combination of bytes produces it — and this tool tells you so rather than returning nonsense. A remainder of two or three is a valid unpadded encoding, and gets padded silently.

Common questions

Is my data uploaded?
No. Encoding and decoding happen in your browser and the page makes no network requests at all. See the privacy policy.
Why does my decoded text look like gibberish?
Either it was not text to begin with — a compressed or encrypted payload decodes to bytes that are not valid UTF-8 — or it was encoded in a different character set. This tool refuses to guess: it reports invalid UTF-8 as an error rather than filling your output with replacement characters.
Can I encode a file?
Not on this page yet. For a data URI you need the MIME type prefix as well, which is a different job from encoding text.
Is Base64 the same as Base64url or Base32?
Base64url is the URL-safe variant described above. Base32 uses a 32-character alphabet, is case-insensitive and roughly 60% larger than the input — chosen when data has to survive being read aloud or typed by hand.