Base64 Encoder and Decoder
Handles emoji and every other script, which most converters cannot.
16 bytes in, 24 characters out
Most online base64 tools are a wrapper around the browser’s btoa, which only handles Latin-1 and throws on any character above U+00FF. That means an emoji, a Chinese character or a curly quote breaks them. This converts to UTF-8 bytes first, so anything Unicode can express round-trips unchanged.
Decoding is deliberately strict about what it calls text. Base64 that holds an image or a key decodes to bytes that are not valid UTF-8, and the honest answer is to say so rather than return a screenful of replacement characters.
How the Base64 Encoder and Decoder works
Base64 and URL encoding in both directions, in a converter that does not fall over on non-English text. The browser's built-in base64 functions only handle Latin-1, which is why so many online tools break on an emoji or a curly quote; this one goes through UTF-8 bytes, so anything Unicode can express round-trips unchanged.
Also known as: base64 encode · base64 decode online · url encoder decoder · percent encoding tool · base64 url safe converter
Why so many base64 tools break on an emoji
Browsers give you btoa and atob, and they are older than Unicode's dominance on the web. They operate on binary strings, meaning strings where every character is a single byte, so any character above U+00FF throws an InvalidCharacterError. That covers every emoji, every CJK character, every accented letter beyond Latin-1, and the curly quotes that word processors insert automatically.
The usual patch is the escape and unescape trick: percent-encode the string, unescape it into a binary string, then btoa that. It works often enough to ship and it is wrong. escape and unescape are deprecated, they use a percent-encoding scheme that is not UTF-8, and the results decode correctly only if whatever reads them applies the same reverse trick. Send that base64 to a Python service and you get mojibake.
The correct route is through bytes and it is no harder. TextEncoder turns the string into UTF-8 bytes, those bytes get base64-encoded, and TextDecoder reverses it. Anything Unicode can express survives, and the output is the same base64 any other language would produce for the same text. That is what happens here, and it is checked against the seven test vectors published in RFC 4648 section 10, which exist precisely so implementations can be verified rather than assumed.
Two alphabets, and when the difference bites
Standard base64 uses A-Z, a-z, 0-9, plus and slash, with equals signs padding the output to a multiple of four. Two of those characters are actively hostile to URLs. A plus sign in a query string is decoded as a space by essentially every form parser, so base64 pasted into a URL comes back with spaces in it and fails to decode. A slash ends a path segment.
RFC 4648 section 5 defines the URL-safe alphabet for exactly this: minus for plus, underscore for slash. Padding is usually dropped as well, since an equals sign has to be percent-encoded in a URL, and the padding carries no information, the length of the data already implies it. JSON Web Tokens use this variant, which is why a JWT is full of hyphens and underscores and has no equals signs at the end of its segments.
Decoding here accepts either alphabet without being told which, and tolerates missing padding and stray whitespace, because real base64 arrives wrapped across lines out of email headers and PEM files.
Saying when the data is not text
Base64 exists to carry binary through text-only channels, so a great deal of the base64 you encounter is not text at all. It is a PNG, a certificate, a font, a protobuf message.
Decode that as UTF-8 with the usual lenient settings and every invalid byte is replaced by U+FFFD, the replacement character. You get a screenful of black diamonds and question marks, and nothing tells you that the decode failed rather than that the data was strange. Plenty of tools do exactly this.
Decoding here is strict, so invalid UTF-8 is reported as what it is: a count of bytes that are not text. That is more useful than a wall of replacement characters, and it tells you the base64 itself was probably fine.
URL encoding has three answers, not one
Percent-encoding looks like one operation and is three, depending on how much of the string is structure and how much is data.
encodeURIComponent is the one you want almost always. It encodes everything that carries meaning in a URL, including ampersand, equals, question mark and slash, so the result is safe to drop in as a single query value or path segment. encodeURI is for a whole address: it leaves the structural characters alone so the URL still works, and is the right choice only when you are encoding something that already is a URL.
The third case is a wrinkle worth knowing. encodeURIComponent leaves five characters untouched: exclamation mark, apostrophe, opening and closing parenthesis, and asterisk. RFC 3986 classes them as sub-delimiters and they are legal in a query string, so this is correct behaviour. It also breaks things. OAuth 1.0 signature base strings require them encoded, some CDN cache keys treat them inconsistently, and a number of server-side parsers choke. The strict mode here encodes them, which is what the OAuth specification's own reference implementations do.
Frequently asked questions
Why do other base64 tools break on emoji?
Because they wrap the browser's btoa, which only accepts characters up to U+00FF and throws on anything above it. Tools that patch around the error with escape and unescape produce output that decodes to mojibake somewhere else, which is worse than failing. Encoding to UTF-8 bytes first avoids the whole problem.
What is the URL-safe alphabet?
RFC 4648 section 5 swaps + for - and / for _, because a plus becomes a space in a query string and a slash breaks a path segment. Padding is dropped too, since an equals sign has to be percent-encoded in a URL anyway. Decoding here accepts either alphabet without being told which.
Why does decoding sometimes say the data is not text?
Because it is not. Base64 holding an image, a certificate or a key decodes to bytes that are not valid UTF-8, and the honest answer is to say so. Decoders that carry on regardless replace every bad byte with a question mark and give you a screenful of nonsense with no indication that anything went wrong.
Which URL encoding mode should I use?
Component for a single query value or path segment, which is what you want almost every time. Strict adds the five characters encodeURIComponent leaves alone, exclamation mark, apostrophe, brackets and asterisk, which OAuth signing and some server parsers expect encoded. Whole URL leaves the structural characters intact and is for encoding an address rather than a value inside one.
Is base64 encryption?
No, and it is worth being blunt about it. Base64 is an encoding, reversible by anyone in one step and by this page in particular. It exists to move binary data through channels that only carry text, such as email or a JSON field. It provides no secrecy whatever.
Related calculators
JSON Formatter
Format, minify and validate, with errors located to the exact line and column.
OpenUUID Generator
Version 4 UUIDs, correct to RFC 9562, as many as you need.
OpenPassword Generator
Cryptographically random, generated in your browser, never sent anywhere.
Open