Android Base64 NO_WRAP

Android's Base64.encodeToString(bytes, Base64.DEFAULT) inserts a newline every 76 characters, which breaks JSON bodies, HTTP headers, and URLs. Use Base64.NO_WRAP instead. For decoding, use matching flags (NO_WRAP, plus URL_SAFE for -/_). The tool below shows the difference.

TEXT
BASE64
Waiting for input

Why does Android Base64 add newlines?

The flag you pass to android.util.Base64 controls formatting, and the most common one — Base64.DEFAULT — follows the old MIME convention. That means it inserts a line break (\n) after every 76 characters of output, plus a trailing newline at the end. Inside an email that's fine, but it silently corrupts a Base64 value the moment you drop it into a JSON string, an HTTP header, or a URL query parameter — the embedded newlines are illegal or get stripped, and the far end fails to decode. Toggle the demo above between DEFAULT (wrapped) and NO_WRAP with a long input to see the line breaks appear and disappear.

Use Base64.NO_WRAP

Pass Base64.NO_WRAP instead of Base64.DEFAULT and the output is one continuous line with no breaks:

// Kotlin
import android.util.Base64

val bytes = "Hello".toByteArray(Charsets.UTF_8)
val encoded = Base64.encodeToString(bytes, Base64.NO_WRAP)  // one line, no \n

// Combine flags with bitwise OR when you also need URL-safe / no padding:
val token = Base64.encodeToString(bytes, Base64.NO_WRAP or Base64.URL_SAFE)
// Java
import android.util.Base64;

byte[] bytes = "Hello".getBytes(StandardCharsets.UTF_8);
String encoded = Base64.encodeToString(bytes, Base64.NO_WRAP);   // single line

// Multiple flags:
String token = Base64.encodeToString(bytes, Base64.NO_WRAP | Base64.URL_SAFE);

Decoding: match the flags

Decoding must use the same flags the data was encoded with, or you get an IllegalArgumentException: bad base-64. Decode NO_WRAP data with NO_WRAP; add URL_SAFE for tokens that use - and _:

// Kotlin — decode
val bytes = Base64.decode(encoded, Base64.NO_WRAP)
val text = String(bytes, Charsets.UTF_8)

// URL-safe token (contains - or _):
val raw = Base64.decode(token, Base64.NO_WRAP or Base64.URL_SAFE)
// Java — decode
byte[] bytes = Base64.decode(encoded, Base64.NO_WRAP);
String text = new String(bytes, StandardCharsets.UTF_8);

// Wrong flags -> java.lang.IllegalArgumentException: bad base-64
byte[] raw = Base64.decode(token, Base64.NO_WRAP | Base64.URL_SAFE);

Tip: Android's decoder is fairly tolerant of whitespace on input, so decoding still works even if the string was wrapped — the newline problem bites on the encode side, when the wrapped string travels through a transport that can't carry newlines.

android.util.Base64 vs java.util.Base64

There are two Base64 classes on Android and they behave differently by default:

// java.util.Base64 (API 26+) — no wrapping to worry about
import java.util.Base64;
String encoded = Base64.getEncoder().encodeToString(bytes);          // single line
byte[] back    = Base64.getDecoder().decode(encoded);
String urlTok  = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);

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 does Android Base64.encodeToString add newlines?

The default flag, Base64.DEFAULT, follows MIME conventions and inserts a line break (\n) every 76 characters, plus a trailing newline. That wrapping breaks JSON bodies, HTTP headers, and URLs. Use Base64.NO_WRAP to produce a single unbroken line.

What is the difference between Base64.DEFAULT and Base64.NO_WRAP?

Base64.DEFAULT wraps output at 76 characters with newlines; Base64.NO_WRAP produces one continuous line with no line breaks. For transport in JSON, headers, or URLs you almost always want NO_WRAP.

Why do I get IllegalArgumentException when decoding Android Base64?

You're decoding with different flags than you encoded with — for example decoding URL-safe Base64 without Base64.URL_SAFE, or feeding padded input to a NO_PADDING decoder. Match the decode flags to how the string was produced.

Should I use android.util.Base64 or java.util.Base64?

On modern Android (API 26+) java.util.Base64 is available and its basic encoder returns single-line output by default, so there's no 76-character wrapping to fight. android.util.Base64 works on all API levels but defaults to MIME wrapping, so you must pass NO_WRAP.

Need plain Base64 encode/decode?

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

Open base64.dev →