Base64 Encoder/Decoder
Encode text to Base64 or decode Base64 back to readable text, with full UTF-8 support. Updates live as you type.
About the Base64 Encoder/Decoder
Base64 encoding maps raw bytes onto a 64-character alphabet so binary-ish data can travel safely through text-only channels like URLs, JSON fields, or email headers. Unlike a lot of quick implementations, this one handles UTF-8 properly, so accented letters, emoji, and non-Latin scripts round-trip correctly instead of turning into garbled characters, and the conversion happens locally without any upload.
Why raw btoa() breaks on emoji and accented characters
The browser's native btoa() function only understands "binary strings," text where every character's code point fits in a single byte, 0 to 255. The moment your input contains a character outside that narrow range, an emoji, a Chinese character, an accented letter like é, calling btoa() directly either throws an error or silently produces corrupted output, because it was never designed to handle full Unicode. This tool works around that with a well-known technique: encodeURIComponent(text) first converts the string into its UTF-8 byte representation, percent-escaped into plain ASCII (so é becomes something like %C3%A9), and then unescape() converts those percent-escapes back into raw single-byte characters, exactly the "binary string" format btoa() expects. Decoding runs the same trick in reverse: atob() unpacks the Base64 back into that byte-string form, escape() re-escapes any byte 128 or above into percent-encoded form, and decodeURIComponent() reassembles the proper Unicode characters from those bytes.
A deliberate use of an officially deprecated pair of functions
escape() and unescape() are marked as legacy, deprecated functions in the JavaScript specification, and general advice is to avoid them for URL encoding or general string escaping, where encodeURIComponent() alone is the correct modern tool. But for this one narrow purpose, bridging UTF-8 text and btoa()/atob()'s byte-string requirement, they remain the simplest, most broadly compatible technique available, and it's still the workaround commonly documented for exactly this problem. It's a case where "deprecated" doesn't mean "broken" or "unsafe to use here," just that the functions shouldn't be reached for outside this specific, well-understood pairing.
Base64 is encoding, not encryption, and that distinction matters
Base64 output looks scrambled and unreadable at a glance, which leads a lot of people to mistake it for some form of security or obfuscation. It isn't. Base64 is a fully reversible, publicly known, one-to-one mapping with no key or secret involved at all, anyone who recognizes a Base64 string (or just pastes it into a decoder like this one) can recover the original text instantly. It's purely a transport-safety mechanism, making sure binary-ish data survives being carried through text-only systems intact, not a way to hide or protect sensitive information. If you need actual confidentiality, that's what the site's separate Text Encryption Tool exists for.
Why encoded output is always roughly 33% longer than the input
Base64's 64-character alphabet exists because 2^6 = 64, each Base64 character encodes exactly 6 bits of information, and since 3 raw bytes equal exactly 24 bits, every 3 bytes of input map cleanly onto 4 Base64 characters. That fixed 3-to-4 ratio is where the roughly 33% size increase comes from, it's a structural property of the encoding, not a quirk of any particular implementation. When the input's byte length isn't an exact multiple of 3, one or two = padding characters get appended at the end to mark that the final group was filled out with placeholder bits rather than real data.
What happens when you decode invalid input
Not every string of characters is valid Base64, the alphabet only permits A-Z, a-z, 0-9, plus, slash, and padding equals signs, so pasting arbitrary text, malformed data, or a string with incorrect padding into decode mode will cause the browser's native atob() function to throw an error rather than return a nonsense result. This tool catches that error and shows a plain "Invalid Base64 input" message instead of letting the page break or silently displaying garbage, which is a more useful failure mode than either crashing outright or guessing at a wrong answer.
Frequently Asked Questions
Why does raw btoa() fail or produce garbage on emoji and accented characters?
btoa() only handles "binary strings" where every character fits in a single byte (0-255). Characters outside that range, like emoji or accented letters, need multiple bytes in UTF-8, which btoa() can't process directly, causing errors or corrupted output without the UTF-8 conversion trick this tool applies first.
Is it safe to use escape() and unescape() even though they're deprecated?
For this specific purpose, bridging UTF-8 text into the byte-string format btoa()/atob() expect, yes, it remains the standard documented workaround. The deprecation warning applies to using them for general string escaping or URL encoding, where encodeURIComponent() is the correct modern choice instead.
Is Base64 a form of encryption or security?
No. Base64 is a fully reversible, publicly known encoding scheme with no secret key involved, anyone can decode it instantly. It only ensures data survives text-only transport channels intact, it provides zero confidentiality. Use actual encryption if you need to protect sensitive information.
Why is Base64-encoded output always longer than the original text?
Each Base64 character represents 6 bits, and 3 bytes of input (24 bits) map to exactly 4 Base64 characters, a fixed 3-to-4 ratio that produces roughly 33% size growth. This is a structural property of the 64-character alphabet, not specific to any implementation.
What do the = characters at the end of some Base64 strings mean?
They're padding, added when the input's byte length isn't an exact multiple of 3. One or two = characters signal that the final 4-character group was filled out with placeholder bits rather than representing real encoded data.
What does the Swap button actually do?
It takes whatever is currently in the output box, moves it into the input box, and flips the mode between encode and decode. This is a quick way to verify a round trip, encoding text and then swapping to decode should return exactly your original input.