How to Encode and Decode Base64 (and Fix Mojibake)
Base64 shows up in API payloads, JWTs, inline images and email attachments. The rules are simple, which is exactly why the same two mistakes keep happening: expecting it to hide data, and getting garbled text when the character encoding does not match.
- Base64 is an encoding, not encryption - anyone can reverse it in one step, so it must never be used to protect passwords or secrets
- Encoded output is about 33% larger than the input, because every 3 bytes become 4 characters
- Standard Base64 uses + and /, which are reserved characters in URLs and filenames, so URL-safe Base64 replaces them with - and _
- Trailing = characters only pad the length to a multiple of 4; many decoders accept input without them, but not all do
- Garbled text is almost always an encoding mismatch, such as encoding UTF-8 bytes but decoding them as Latin-1 or GBK
#Two facts that explain almost every Base64 surprise
Base64 is an encoding, not encryption. It converts arbitrary bytes into 64 safe, printable characters. No key is involved, so anyone holding the string can recover the original in one step. Using it to "hide" an API key or a password protects nothing.
Base64 makes data bigger, not smaller. Every 3 bytes of input become 4 characters of output, so the result is 4/3 the size - roughly 33% larger. A 1 MB image becomes about 1.33 MB, plus the DataURL prefix on top.
Those two facts explain the surprises that follow: why inlining images bloats your CSS, and why a reviewer could read your "encrypted" query parameter at a glance.
#Encode or decode in three steps
- Open the Base64 Encoder / Decoder and paste your content.
- Choose the direction. The tool tries to detect it - valid Base64 input is decoded - but switch manually when you want to be certain.
- For non-ASCII text, confirm the charset is UTF-8, then copy the output.
Working with an image or a PDF? Use Image to Base64 instead. It generates the full data:image/png;base64, prefix for you and can convert a DataURL back into a file.
#Three things called "Base64" - do not mix them up
There are three alphabets in circulation. Picking the wrong one produces the classic "this string is definitely correct but will not decode" problem.
| Variant | How it differs | Where you meet it |
|---|---|---|
| Standard Base64 | Uses + and /, padded with = | Email (MIME), API fields, config values |
| URL-safe Base64 | Replaces + / with - _, usually unpadded | Query strings, filenames, JWT segments |
| DataURL | Standard Base64 prefixed with data:<MIME>;base64, | Inline images and fonts in HTML / CSS |
How to tell them apart: if the string contains - or _, it is URL-safe Base64 and needs the matching alphabet. If it contains + or /, it is standard Base64 and must not be put into a URL as-is.
Putting standard Base64 into a query string corrupts it. + is decoded as a space by many servers, and / looks like a path separator. The receiver ends up with a different string than you sent. Convert to URL-safe Base64 first, or escape the whole value with the URL Encoder / Decoder.
#Garbled output: work through this table
Mojibake means the encoder and the decoder disagreed about the character set. It is not a broken tool.
| What you see | What actually happened | Fix |
|---|---|---|
Output like 测试 | UTF-8 bytes were decoded as Latin-1 | Re-decode with UTF-8 selected |
Output like 锟斤拷 or runs of ? | GBK bytes were decoded as UTF-8 | Re-encode the source as UTF-8 first |
| "Invalid character" while encoding | An old API that only accepts Latin-1 | UTF-8 encode, then Base64 encode, as two steps |
| Decoding succeeds but the tail is wrong | The string was truncated, or + became a space | Verify length against a checksum; use URL-safe Base64 |
One property worth remembering: Base64 carries no checksum. If a character is lost in transit, decoding still "succeeds" - the last few bytes are simply wrong. For anything that matters, compare hashes of the original data (SHA Hash or MD5 Hash) rather than eyeballing Base64 strings.
#Which tool do you actually need?
| Goal | Tool | Why |
|---|---|---|
| Convert text or binary to Base64 and back | Base64 Encoder / Decoder | The everyday choice, handles large input |
| Embed an image as a DataURL | Image to Base64 | Adds the MIME prefix, and reverses it back to an image |
| Put a value into a URL query string | URL Encoder / Decoder | RFC 3986 percent-encoding - a different mechanism entirely |
Chinese text became \u4e2d\u6587 | Unicode Converter | That is Unicode escaping, not Base64 |
< and > turned into entities | HTML Entity Escape | For safe rendering, unrelated to Base64 |
The quick visual test: only letters, digits, +, / and = can be Base64. A % means URL encoding, &# or & means HTML entities, and a \u prefix means Unicode escape.
#Two worked examples
#Reading the payload of a JWT
A JWT is three .-separated segments. The middle one is URL-safe Base64 encoded JSON. Copy that segment out, check whether it uses - and _ so you pick the right alphabet, decode it, and you get a readable JSON object with fields like sub, exp and iat.
JWT payloads are encoded, not encrypted. Anyone can decode them. Never put phone numbers, national ID numbers or other personal data directly in a JWT payload - the signature prevents tampering, not reading.
#Sending binary through a text-only API
Some older APIs only accept printable characters, so images or archives must be Base64 encoded into a JSON string field, then decoded back to bytes on the server. Watch the size limit: a 10 MB file becomes a 13.3 MB field, which will happily exceed a gateway request-body cap.
#Frequently asked questions
#Can Base64 be used to store passwords?
No. It is reversible by anyone with no key and no computational cost. Store passwords as salted hashes on the server instead, and protect data in transit with real encryption such as AES / DES Encrypt.
#Is it safe to strip the trailing = characters?
Usually, but it depends on the decoder. The = only pads the length to a multiple of 4, and many decoders infer it. Not all implementations do, so keep the padding unless you control both ends. Conversely, if a decoder complains about an invalid length, check whether something stripped the = in transit.
#Why does Base64 output grow by 33%?
The alphabet has 64 symbols, so one character carries 6 bits of information (2^6 = 64), while a byte is 8 bits. Every 3 bytes (24 bits) therefore need 4 characters (24 bits). The result is 4/3 of the original - the price of using only printable characters.
#Does Base64 compress data?
No, it does the opposite. When a tool advertises "Base64 compression", it is really gzip-compressing first and Base64 encoding the result - two separate steps. Base64 itself only converts bytes into safe characters.
#Should I inline images as Base64 or link them?
It depends on size. Icons under a few KB benefit from inlining because they remove a request. Large images bloat the CSS or HTML file and cannot be cached independently. A workable threshold is inline below 10 KB, link above it.
Tools used in this guide
Encode and decode Base64 text with UTF-8 support; use the image tool for files
Open tool →URL Encode/DecodeRFC 3986 URL percent-encoding
Open tool →Image to Base64Convert images to/from Base64 DataURL
Open tool →Unicode ConverterConvert Chinese to/from \uXXXX escape sequences
Open tool →HTML Entity EscapeConvert < > & HTML entities
Open tool →