React Native atob / btoa Polyfill

React Native's JS engines (Hermes/JSC) don't include atob/btoa, so calling them throws ReferenceError: atob is not defined. Fix it by polyfilling with the base-64 package (or Buffer) at app startup. The working encoder/decoder below shows the exact output you should get.

TEXT
BASE64
Waiting for input

Why is atob not defined in React Native?

atob and btoa are Web APIs — they're supplied by the browser's global environment, not by JavaScript itself. React Native runs your code in Hermes or JavaScriptCore, which are JS engines, not browsers, so those globals simply don't exist. Any call to atob('...') or btoa('...') throws ReferenceError: atob is not defined (or btoa is not defined). The fix is to define them yourself once, at startup.

Polyfill with the base-64 package

The simplest, most portable fix is the tiny pure-JS base-64 package. Install it, then assign the globals in your entry file (index.js or App.tsx) before any code that uses them:

// npm install base-64
import { decode, encode } from 'base-64';

if (typeof global.atob === 'undefined') global.atob = decode;
if (typeof global.btoa === 'undefined') global.btoa = encode;

// Now this works anywhere in the app:
const b64 = btoa('Hello');   // "SGVsbG8="
const txt = atob('SGVsbG8='); // "Hello"

Or use Buffer

If your project already shims Node's Buffer (via react-native-buffer or a Metro resolver), you can skip atob/btoa entirely. Buffer is UTF-8 aware, which avoids the Unicode pitfalls below:

import { Buffer } from 'buffer';

// Encode text -> Base64
const b64 = Buffer.from('Hello', 'utf8').toString('base64'); // "SGVsbG8="

// Decode Base64 -> text
const txt = Buffer.from('SGVsbG8=', 'base64').toString('utf8'); // "Hello"

Unicode-safe encoding

atob and btoa are latin1-only: they treat each character as a single byte, so anything above code point 255 — emoji, accented letters, CJK — throws "The string to be encoded contains characters outside of the Latin1 range" or corrupts silently. For real Unicode, convert to UTF-8 bytes first with TextEncoder, then Base64 those bytes:

import { encode } from 'base-64';

function utf8ToBase64(str) {
  const bytes = new TextEncoder().encode(str);        // UTF-8 bytes
  let bin = '';
  bytes.forEach((b) => { bin += String.fromCharCode(b); });
  return encode(bin);                                 // base-64 over latin1 bytes
}

utf8ToBase64('Héllo 👋'); // correct, round-trips cleanly

Note that TextEncoder itself may need a polyfill on older Hermes; Buffer.from(str, 'utf8').toString('base64') is a drop-in alternative that is already UTF-8 correct.

react-native-quick-base64 for large data

The pure-JS base-64 package is fine for tokens and short strings, but it gets slow for large payloads (images, files, big blobs) because it runs on the JS thread. For those, react-native-quick-base64 is a JSI-native implementation that is dramatically faster and can also install the globals for you:

// npm install react-native-quick-base64
import { btoa, atob } from 'react-native-quick-base64';
// or install the globals in one call:
import 'react-native-quick-base64/install';

const big = btoa(hugeString); // native speed, no JS-thread stall

Is this private?

Yes. The encoder/decoder runs fully in your browser with JavaScript — text is encoded and decoded locally and nothing is uploaded to any server. You can confirm in DevTools → Network: encoding fires no request.

Frequently asked questions

Why is atob not defined in React Native?

atob and btoa are Web APIs provided by browsers. React Native's JavaScript engines (Hermes and JSC) aren't browsers and don't include them, so calling atob or btoa throws ReferenceError: atob is not defined. You must polyfill them.

How do I polyfill atob and btoa in React Native?

Install the base-64 package and, in your entry file, assign the globals before anything uses them: import {decode, encode} from 'base-64'; global.atob = decode; global.btoa = encode;. From then on atob and btoa work everywhere in the app.

Can I use Buffer instead of a polyfill?

Yes. With a Buffer polyfill in place, Buffer.from(str, 'base64').toString() decodes and Buffer.from(str).toString('base64') encodes. Buffer is also UTF-8 aware, unlike atob/btoa, which are latin1-only.

Why does btoa break on emoji or accented characters?

atob and btoa operate on latin1 (one byte per character), so any character above code point 255 throws or corrupts. For Unicode, encode the string to UTF-8 bytes first with TextEncoder (or Buffer) and Base64 those bytes instead of calling btoa on the raw string.

Need plain Base64 encode/decode?

The main base64.dev tool handles text, files, and URL-safe mode with auto-detect.

Open base64.dev →