Base64 Encoder & Decoder

Nothing you enter here is stored, logged or shared.

Encode text to Base64 or decode it back. Unicode is handled correctly, so Japanese, Chinese, Korean and emoji all round-trip without corruption.

How to use

  1. Choose encode or decode.
  2. Paste your text or Base64 string into the input field.
  3. Copy the result with the copy button.

What Base64 is for

Base64 rewrites arbitrary bytes using 64 characters that survive any text channel. It takes three bytes at a time, splits those 24 bits into four groups of six, and maps each group to one character from A-Z, a-z, 0-9 and two symbols. Four characters out for every three bytes in, so the result is about 33% larger than the original, before line breaks.

The point is transport, not secrecy. Base64 was designed for channels that mangle raw bytes: mail systems that strip the high bit, protocols that treat certain control characters as commands, formats that have to be plain text. It is not encryption and not compression, and anything encoded is trivially readable by anyone who cares to decode it. Anyone treating a Base64 string as if it were protected has misunderstood it, which is a mistake this decoder makes easy to demonstrate.

Padding and the two alphabets

When the input does not divide evenly into three bytes, the output is padded with one or two = characters so its length is a multiple of four. Some producers omit the padding, and this decoder adds it back rather than rejecting the input, since the correct amount is implied by the length.

The standard alphabet ends in + and /, both of which have meaning in a URL and become %2B and %2F once escaped, which is ugly and error-prone in a query string or a filename. RFC 4648 section 5 therefore defines a URL-safe variant using - and _ instead, usually with the padding dropped since = also needs escaping. This is the variant JWTs use for every segment. Encoding here offers both; decoding detects which alphabet you pasted and does not require you to say.

Unicode, and the btoa trap

Browsers have had a built-in btoa function for decades, and it does not do what most people assume. It operates on Latin-1: every character in the input must have a code point below 256, and anything else throws InvalidCharacterError. Pass it a single Japanese character, a Cyrillic name or an emoji and it fails outright.

The workaround people find first is to escape the string before encoding, which mangles anything outside ASCII into a different byte sequence that decodes to garbage on the other side. The correct approach, and the one used here, is to convert the text to UTF-8 bytes with TextEncoder first and encode those bytes. That is why any script round-trips through this tool unchanged.

Decoding runs the reverse, and refuses to guess. If the decoded bytes are not valid UTF-8, you are told they are binary rather than shown a string full of replacement characters. That usually means the payload is an image, an archive, a protobuf message or a ciphertext, and the answer is to save the bytes rather than read them as text.

When not to use it

Base64 is the wrong tool for storing secrets, because it protects nothing. It is also a poor default for embedding large assets: a data URI for an image adds a third to its size, cannot be cached separately from the document that carries it, and blocks the page while it parses.

Where it earns its place is in the small and awkward cases: a certificate in PEM form, a signature, a binary field inside a JSON body, a short inline icon, a token segment.

Three bytes in, four characters out

The encoding is easier to trust once you have done it by hand once. Take the three ASCII letters Man: their byte values are 77, 97 and 110, which in binary are 01001101, 01100001 and 01101110. Write those 24 bits in a row and cut them into four groups of six instead of three groups of eight: 010011, 010110, 000101, 101110. Read each group as a number - 19, 22, 5, 46 - and look it up in the alphabet A-Z, a-z, 0-9, + and /, where index 0 is A and index 26 is a. The result is TWFu.

Every property of Base64 falls out of that arithmetic. Six bits per character is why the alphabet has exactly 64 entries. Four characters per three bytes is why the output is a third larger. And the padding exists because the last group may be short: one leftover byte produces two characters plus ==, two leftover bytes produce three characters plus =.

Decoding is the same operation in reverse, which is why any Base64 string whose length is not a multiple of four is either padded, truncated, or was produced by an encoder that dropped the padding on purpose.

Where you meet it in real systems

PEM files - certificates, CSRs, private keys - are Base64 with a header and footer line and a line break every 64 characters. That line length is a MIME convention rather than anything Base64 requires, and decoders are expected to ignore the breaks.

HTTP Basic authentication sends username:password Base64-encoded in the Authorization header, which is exactly why Basic auth over plain HTTP is equivalent to sending the password in clear text. Email attachments have used Base64 since MIME was defined in 1992, for the original reason: mail servers of the era could not be trusted with arbitrary bytes.

Data URIs embed a whole file into a document - data:image/png;base64, followed by the payload - and JSON APIs use Base64 whenever a field has to carry bytes, since JSON has no binary type. JWT segments use the URL-safe variant without padding, and the Docker config, Kubernetes secrets and many CI systems store credentials Base64-encoded, which is storage, not protection.

Size, memory and large files

The 33% expansion is the headline cost and usually the smallest one. Base64 text compresses worse than the bytes it came from, because the encoding destroys byte-level patterns that a compressor would otherwise exploit, so a gzipped Base64 payload is typically larger than the gzipped original.

Memory is the sharper constraint in a browser. Encoding a file means holding the bytes and the resulting string at once, and the string is a third larger again, so a 100 MB file can need several hundred megabytes before anything is sent. Streaming APIs - reading a file in chunks and encoding each - avoid that, provided each chunk is a multiple of three bytes so the padding only appears at the very end.

For anything big, the better answer is usually not to encode at all: send the file as multipart form data or as a raw body, and keep Base64 for the small awkward values that have to travel inside a text format.

The related alphabets and why they exist

Base32 uses 32 characters and produces output 60% larger than the input, which sounds like a poor trade until you need something a person can read aloud or type. It is case-insensitive, avoids easily confused characters, and is what TOTP secrets and onion addresses use.

Base58 drops 0, O, I, l and the two symbols so that a string can be copied by eye without ambiguity; Bitcoin addresses are the best-known use. Base85, or Ascii85, packs four bytes into five characters and is denser than Base64 at the cost of using punctuation that many formats would then have to escape, which is why it survives mainly inside PDF and PostScript.

The pattern is consistent: every one of these trades density against the constraints of the channel. Base64 sits where it does because it is dense enough to be worth the trouble and safe in the widest range of text channels.

Debugging a payload you were handed

A useful first question about any opaque string is whether it is Base64 at all. Three signs are reliable: the length is a multiple of four or ends in one or two equals signs, the alphabet is limited to letters, digits and two symbols, and decoding produces either readable text or a recognisable file header rather than noise.

Those headers are worth knowing by sight in their encoded form, because they identify the content before you save it. A decoded payload starting with the bytes 89 50 4E 47 is a PNG; FF D8 FF is a JPEG; 50 4B 03 04 is a zip, which includes every Office document; 25 50 44 46 is a PDF. In Base64 form, a string beginning iVBORw0KGgo is a PNG and /9j/ is a JPEG, and both come up constantly in API payloads and data URIs.

When decoding produces neither text nor a known header, the usual explanations are that the string is URL-safe Base64 being decoded with the standard alphabet, that it has been encoded twice, or that it is not Base64 but hex or base32. Each is distinguishable in a second: URL-safe strings contain minus or underscore, doubly-encoded ones decode to another Base64-looking string, and hex uses only sixteen characters.

Frequently asked questions

Does this work with non-English text?
Yes. Input is converted to UTF-8 before encoding, so Japanese, Chinese, Korean, accented Latin and emoji all encode and decode correctly. Many Base64 tools use the browser btoa function directly, which throws an error on any character outside Latin-1.
What is URL-safe Base64?
A variant defined in RFC 4648 that replaces + with - and / with _, and usually drops the trailing = padding, so the result can be used in a URL or filename without escaping. Tick the URL-safe box when encoding; decoding accepts either alphabet automatically.
Why does decoding say the result is binary data?
The Base64 was valid but the bytes it contains are not UTF-8 text, which usually means it encodes an image, an archive or an encrypted payload. Rather than showing corrupted characters, the tool tells you what happened.
Do I need to include the padding characters?
No. Missing = padding is added automatically before decoding, and whitespace or line breaks in pasted input are ignored.
Is what I paste sent anywhere?
No. Both directions run in the page. Base64 strings are very often credentials in transit - a basic auth header, a service account key, a certificate - so a decoder that shipped them to a server would be a poor bargain.

Last updated:

Report a problem

Include the steps, expected result, and actual result. Remove secrets and personal data.

Related tools

Related articles