A virtual teacher who reveals to you the great secrets of Base64

Implementing Unicode support for btoa() and atob()

By default JavaScript built-in functions btoa and atob do not support Unicode strings, because these functions treat all characters as 16-bit-encoded strings (that is, are accepted only characters from the extended ASCII table, up to 255 char code). Thus, trying to encode a multibyte character to Base64, the btoa function will throw exception “Character Out Of Range” or “Invalid Character Error”. On other hand, trying to decode a Base64 string that contains multibyte characters, the atob function will return some “weird” characters.

To bypass this limitation we should apply some hacks. For example, on the MDN portal are provided atou and utoa functions.

/**
 * ASCII to Unicode (decode Base64 to original data)
 * @param {string} b64
 * @return {string}
 */
function atou(b64) {
  return decodeURIComponent(escape(atob(b64)));
}
/**
 * Unicode to ASCII (encode data to Base64)
 * @param {string} data
 * @return {string}
 */
function utoa(data) {
  return btoa(unescape(encodeURIComponent(data)));
}

Let’s do some tests, to be sure that the functions above support Unicode strings:

// Both the “pi” and the “approximately equal” symbols are Unicode characters
// As you can see, btoa() fails to encode `str`, while utoa() works like a charm
var str = 'π ≈ 3.14159';
console.log(btoa(str)); //-> "InvalidCharacterError: String contains an invalid character"
console.log(utoa(str)); //-> "z4Ag4omIIDMuMTQxNTk="

// This is the Base64 value for `str` above (I encoded it using the https://base64.guru/converter)
// As you can see, atob() decodes it but return wrong result, while atou() does it properly
var b64 = 'z4Ag4omIIDMuMTQxNTk=';
console.log(atob(b64)); //-> "� � 3.14159"
console.log(atou(b64)); //-> "π ≈ 3.14159"

For more info, please check the MDN documentation: Base64 encoding and decoding.

Comments (3)

I hope you enjoy this discussion. In any case, I ask you to join it.

  • Mar,
    Hi!

    Thanks for your posts!

    I'm trying to decode a GIF to base64, using this utoa() function but it doesn't work. Can you tell me how should I do it?

    Thanks!
    • Administrator,
      Hello Mar,
      You do not need these polyfills to encode or decode binary data. In your case is more than enough to use the built-in functions btoa and atob. Also I recommend you to check these examples to learn how to use them for decoding and encoding binary data. If you still have questions, please do not forget to specify the error you are experiencing.
      • Mar,
        Hi! I found the error, thank you for your reply!
Add new comment

If you have any questions, remarks, need help, or just like this page, please feel free to let me know by leaving a comment using the form bellow.
I will be happy to read every comment and, if necessary, I will do my best to respond as quickly as possible. Of course, spammers are welcome only as readers.