Base64 Encoder & Decoder

Encode text to Base64 and decode it back, in the standard or URL-safe alphabet, without your text leaving the page.

Nothing leaves your browser: the conversion happens here, in the page.

Base64
UXVhY2t5YXJkIPCfpoY=

14 bytes of UTF-8, written as 20 Base64 characters.

Runs in your browser. Nothing you enter is sent anywhere.

How to use it

Type or paste into the box. It converts as you type, and nothing is uploaded.

  1. Choose Encode to turn text into Base64, or Decode to turn Base64 back into text.
  2. When encoding, pick the alphabet: Standard (+ / =) writes + and / and pads with =; URL-safe (- _) writes - and _ with no padding. Decoding reads either.
  3. Press Copy next to the result, or Swap to move the result into the box and flip the direction.

The line under the result counts the bytes. When decoding it also says whether they’re UTF-8 text; if they aren’t, they’re shown as hex and Swap is disabled. Invalid Base64 gives one sentence saying what’s wrong, with the position of a bad character in the box.

Examples

HTTP Basic credentials, with Encode and Standard (+ / =):

Aladdin:open sesame
QWxhZGRpbjpvcGVuIHNlc2FtZQ==

The line under it reads 19 bytes of UTF-8, written as 28 Base64 characters. It’s RFC 7617’s example: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==.

The first segment of a JWT, with Decode:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
{"alg":"HS256","typ":"JWT"}

JWT segments are URL-safe and unpadded, and they decode as they are.

An image as a data URL, with Decode:

data:image/png;base64,iVBORw0KGgo=
89 50 4e 47 0d 0a 1a 0a

The data: header is skipped. The 8 bytes are the PNG signature, which isn’t UTF-8.

Two Base64 strings pasted together, with Decode:

SGVsbG8=IHdvcmxk

The error is The "=" at position 8 isn't at the end, and Base64 padding only comes after the last character. Each half decodes alone (Hello and world), but = marks the end of the data, so encodings can’t be joined.

Good to know

  • Base64 is defined in RFC 4648. Every 3 bytes become 4 characters of 6 bits each. A last group of 1 or 2 bytes becomes 2 or 3 characters, padded with == or = in the standard alphabet. The output is about a third larger than the input.
  • The alphabets differ in two characters. Standard (section 4) uses + and /, which mean something in URLs and paths; base64url (section 5) uses - and _. <<???>> encodes to PDw/Pz8+Pg== in one and PDw_Pz8-Pg in the other.
  • Text is encoded as UTF-8. café is 5 bytes and encodes to Y2Fmw6k=. The browser’s btoa("café") gives Y2Fm6Q== because it treats each character as one Latin-1 byte, and it throws InvalidCharacterError on anything above U+00FF, emoji included.
  • Decoding is lenient where that’s safe. Spaces and line breaks are ignored, so MIME output wrapped at 76 columns (RFC 2045) decodes as pasted. Padding is optional.
  • What it rejects: characters outside both alphabets, = before the end, more than two =, padding that doesn’t complete a group of four, and a length that leaves one character over (Zm9vY has 5). A % usually means it was URL-encoded (%3D is =): URL-decode it first.
  • Bytes are shown as text only when they’re valid UTF-8, as TextDecoder judges it with fatal: true (WHATWG Encoding Standard). Anything else comes out as lowercase hex: most images, a cut-off or overlong character, a surrogate, or a byte that never appears in UTF-8, so +JCAgA== gives f8 90 80 80. Valid isn’t the same as readable: AA== passes as text, but that text is one NUL control character.
  • Spare bits aren’t checked. QQ== and QR== both decode to A; RFC 4648 lets a decoder reject the second.
  • The encoder never inserts line breaks. Line breaks in the box are LF, one 0a byte each. Input is limited to 100,000 characters.

Questions

How do I decode Base64 to text?

Choose Decode and paste the string: the text appears below, or hex if the bytes aren’t UTF-8. Either alphabet works, padded or not.

How do I encode or decode Base64 in the terminal?

Run printf '%s' 'hello' | base64 to encode and base64 --decode to decode, on Linux or macOS. echo hello | base64 gives aGVsbG8K rather than aGVsbG8= because echo adds a newline. GNU base64 also wraps at 76 columns unless you pass -w 0.

How do I Base64-encode a string in JavaScript?

In Node.js, use Buffer.from(text, 'utf8').toString('base64'), or 'base64url' for the unpadded URL-safe form. In the browser, convert to UTF-8 first: btoa(String.fromCharCode(...new TextEncoder().encode(text))) matches this tool, though the spread fails on very long strings.

Why does Base64 end with = or ==?

The = is padding that fills the last group to four characters: one leftover byte gives ==, two give =. It carries no data, so URL-safe encoders, this one included, usually drop it; JWTs must leave it out.

Is Base64 encryption?

No: there’s no key, and anyone can decode it. It carries bytes through text channels like email, JSON and HTTP headers; Basic auth credentials and JWT payloads are readable by anyone who sees them.