DEV Community

Cover image for How to Encode Base64 in JavaScript Without Breaking Unicode
MOUSTAID Hamza
MOUSTAID Hamza

Posted on

How to Encode Base64 in JavaScript Without Breaking Unicode

Base64 encoding is one of those small developer tasks that looks simple until you hit Unicode characters, files, APIs, or URL-safe formats.

In JavaScript, many tutorials show this:

btoa("Hello World");
Enter fullscreen mode Exit fullscreen mode

And yes, it works.

But only for simple ASCII text.

Once you try to encode something like:

"Café 🚀"
Enter fullscreen mode Exit fullscreen mode

you may run into errors or broken output.

In this guide, we’ll cover how Base64 encoding works in JavaScript, when btoa() is enough, when it is not, and how to encode text, Unicode, files, images, and URL-safe Base64 correctly.

You can also test examples quickly with EncodingBase64, a free browser-based Base64 encoder for text, files, images, URL-safe Base64, hex, and URL encoding.


What is Base64 encoding?

Base64 is a way to represent binary data using readable ASCII characters.

It is commonly used when binary data needs to travel through systems that expect text, such as:

  • APIs
  • JSON payloads
  • email attachments
  • HTML/CSS data URIs
  • authentication headers
  • embedded images
  • configuration files

For example:

Hello World
Enter fullscreen mode Exit fullscreen mode

becomes:

SGVsbG8gV29ybGQ=
Enter fullscreen mode Exit fullscreen mode

Base64 does not encrypt data. Anyone can decode it.

It only changes the representation of the data.


Basic Base64 encoding with btoa()

JavaScript includes a built-in function called btoa().

Example:

const text = "Hello World";
const encoded = btoa(text);

console.log(encoded);
// SGVsbG8gV29ybGQ=
Enter fullscreen mode Exit fullscreen mode

To decode it back:

const decoded = atob(encoded);

console.log(decoded);
// Hello World
Enter fullscreen mode Exit fullscreen mode

This is fine for basic ASCII strings.

But there is a problem.


The Unicode problem with btoa()

Try this:

const text = "Café 🚀";
const encoded = btoa(text);

console.log(encoded);
Enter fullscreen mode Exit fullscreen mode

Depending on the environment, you may get an error like:

InvalidCharacterError
Enter fullscreen mode Exit fullscreen mode

Why?

Because btoa() expects a binary string where each character is in the Latin-1 range. It does not directly support full Unicode text.

Modern apps often deal with:

  • accented characters
  • Arabic
  • French
  • Spanish
  • German
  • Portuguese
  • emojis
  • non-Latin scripts

So we need a safer method.


Unicode-safe Base64 encoding

Use TextEncoder to convert the string into UTF-8 bytes first.

function encodeBase64Unicode(text) {
  const bytes = new TextEncoder().encode(text);

  let binary = "";
  bytes.forEach((byte) => {
    binary += String.fromCharCode(byte);
  });

  return btoa(binary);
}

console.log(encodeBase64Unicode("Café 🚀"));
// Q2Fmw6kg8J+agA==
Enter fullscreen mode Exit fullscreen mode

Now the Unicode string is safely converted to UTF-8 before Base64 encoding.


Unicode-safe Base64 decoding

To decode it back properly, use TextDecoder.

function decodeBase64Unicode(base64) {
  const binary = atob(base64);

  const bytes = Uint8Array.from(binary, (char) => {
    return char.charCodeAt(0);
  });

  return new TextDecoder().decode(bytes);
}

const encoded = encodeBase64Unicode("Café 🚀");
const decoded = decodeBase64Unicode(encoded);

console.log(decoded);
// Café 🚀
Enter fullscreen mode Exit fullscreen mode

This is safer for real-world text.


Encoding a file to Base64 in JavaScript

For files, you can use FileReader.

Example with an HTML file input:

<input type="file" id="fileInput" />
Enter fullscreen mode Exit fullscreen mode
const input = document.getElementById("fileInput");

input.addEventListener("change", () => {
  const file = input.files[0];

  if (!file) return;

  const reader = new FileReader();

  reader.onload = () => {
    console.log(reader.result);
  };

  reader.readAsDataURL(file);
});
Enter fullscreen mode Exit fullscreen mode

The result will look like this:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
Enter fullscreen mode Exit fullscreen mode

This is called a data URI.

It includes:

data:[mime-type];base64,[base64-data]
Enter fullscreen mode Exit fullscreen mode

For example:

data:image/png;base64,iVBORw0KGgo...
Enter fullscreen mode Exit fullscreen mode

If you only want the raw Base64 part, remove everything before the comma:

const dataUrl = reader.result;
const rawBase64 = dataUrl.split(",")[1];

console.log(rawBase64);
Enter fullscreen mode Exit fullscreen mode

Encoding an image to Base64

Images are one of the most common Base64 use cases.

You might encode images to Base64 when:

  • embedding a tiny icon in HTML
  • storing a small image in JSON
  • sending an image through an API
  • generating previews
  • creating CSS background images

Example HTML output:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." alt="Example" />
Enter fullscreen mode Exit fullscreen mode

Example CSS output:

.icon {
  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...");
}
Enter fullscreen mode Exit fullscreen mode

This is useful for small images.

But be careful: Base64 increases file size, so it is usually not ideal for large images.

For quick browser-based image conversion, EncodingBase64’s Image to Base64 tool can convert images into raw Base64, data URI, HTML, CSS, or Markdown formats.


What is URL-safe Base64?

Standard Base64 uses characters like:

+
/
=
Enter fullscreen mode Exit fullscreen mode

These characters can be problematic in URLs.

URL-safe Base64 replaces:

+ with -
/ with _
Enter fullscreen mode Exit fullscreen mode

Padding = may also be removed in some systems.

Example helper:

function toBase64Url(base64) {
  return base64
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/g, "");
}

const encoded = encodeBase64Unicode("Hello World");
const urlSafe = toBase64Url(encoded);

console.log(urlSafe);
// SGVsbG8gV29ybGQ
Enter fullscreen mode Exit fullscreen mode

To convert Base64URL back to standard Base64:

function fromBase64Url(base64Url) {
  let base64 = base64Url
    .replace(/-/g, "+")
    .replace(/_/g, "/");

  while (base64.length % 4 !== 0) {
    base64 += "=";
  }

  return base64;
}
Enter fullscreen mode Exit fullscreen mode

Base64URL is commonly used in:

  • JWTs
  • URL tokens
  • authentication flows
  • compact identifiers
  • web-safe encoded data

Common Base64 encoding mistakes

1. Thinking Base64 is encryption

Base64 is not secure. It is reversible.

Do not use it to protect passwords, API keys, or private data.

2. Using btoa() directly with Unicode

This can break:

btoa("Café 🚀");
Enter fullscreen mode Exit fullscreen mode

Use TextEncoder instead.

3. Using standard Base64 in URLs

Standard Base64 can contain +, /, and =. Use Base64URL when the value needs to go inside a URL.

4. Encoding large images unnecessarily

Base64 is usually better for small assets, not large files.

5. Forgetting the MIME type for images

For browser display, this:

iVBORw0KGgo...
Enter fullscreen mode Exit fullscreen mode

may not be enough.

You often need:

data:image/png;base64,iVBORw0KGgo...
Enter fullscreen mode Exit fullscreen mode

Quick answer

Use btoa() only for simple ASCII text.

For Unicode-safe Base64 encoding in JavaScript, convert text to UTF-8 bytes first using TextEncoder, then encode those bytes with btoa().

For files and images, use FileReader.readAsDataURL().

For URLs, convert standard Base64 into Base64URL by replacing + with -, / with _, and optionally removing = padding.


Final thoughts

Base64 encoding is simple in theory, but real-world usage gets more complex when you deal with Unicode, files, images, URLs, and APIs.

For quick testing, debugging, and conversion, a browser-based tool like EncodingBase64 can save time because you can encode text, files, images, URL-safe Base64, hex, and URLs without setting up code.

The key rule to remember:

Base64 is an encoding format, not a security feature.

Use it when you need text-safe data representation, not when you need encryption.

Top comments (0)