AIBOX

Base64 Encoder and Decoder

Encode text to Base64 and decode Base64 back to text, in both directions, with the result updating as you type. Text goes through UTF-8 bytes first — which is the whole point, because the browser's own btoa cannot represent a Chinese character at all and quietly gets accented Latin wrong. Decoding accepts what real systems emit: missing = padding, line breaks, and the URL-safe alphabet. When the bytes you decode are valid Base64 but not text at all, this page tells you that instead of printing replacement characters.

Text → Base64

Any characters at all, including Chinese, Japanese, emoji and accented Latin. The text is turned into UTF-8 bytes before encoding, so what comes out can be read back by any other system. Ctrl/⌘ + Enter encodes.

URL-safe replaces + and / with - and _, which is what fits in a URL.

The trailing = signs carry no information; some systems keep them and some leave them off. Either can be decoded.

Base64 → text

Paste it exactly as you got it. Line breaks, spaces, a missing = and the URL-safe alphabet are all handled — and each one is reported below, so you can see what your input actually was. Ctrl/⌘ + Enter decodes.

Nothing you paste is sent to us — both directions run in this page, in the tab you already have open. See our privacy policy.

How to use it

  1. Pick the direction first. There are two boxes, not one clever one. No tool can reliably tell whether a string like Zm9v is text you want encoded or Base64 you want decoded — it happens to be both, and those two readings give different answers. So you choose, and nothing is guessed.
  2. Paste and read the result as you type. The output updates with every keystroke, so you can see immediately whether the encoding looks the way you expected. The Round trip line decodes the result again and compares it character by character with what you typed, which is a check rather than a feeling.
  3. Read the yellow notes before the result. They are where this tool says what it did on your behalf: whitespace removed, padding added, the URL-safe alphabet detected, and the one real warning — unpaired surrogate code units, which the encoder silently replaces and which therefore do not survive a round trip.
  4. Use the two "instead" buttons to change direction. Copying the result into the other box by hand is the step people get wrong: one stray newline and the Base64 is no longer the Base64.

Why the browser's own btoa is not enough

Every Base64 tool you have used calls the same two browser functions, btoa and atob, or an equivalent. They work on bytes written as characters: each character in the input must be in the range 0–255, one character per byte. That is the Latin-1 idea of text, and it stopped being a safe assumption on the web a long time ago. Two different failures follow, and the second is the dangerous one.

It throws, loudly

A Chinese character like is U+4E2D. There is no single byte for it, so btoa('中') raises an InvalidCharacterError and produces nothing. Annoying, but at least it is honest.

It succeeds, quietly, with the wrong bytes

An accented Latin letter sits below 0xFF, so it is accepted — and encoded as one byte. café becomes Y2Fm6Q==, which decodes to café only if the other side also assumes Latin-1. Anything that follows the modern web — a JSON API, a database, a browser fetch — assumes UTF-8, where é is two bytes, and the correct encoding of café is Y2Fmw6k=. The two strings differ, both look perfectly plausible, and nothing about either one says which convention produced it. That is the defect this page exists to avoid: not a crash, but a confident wrong answer.

The fix is one step, and this page does it in both directions: turn the text into UTF-8 bytes with TextEncoder, encode those bytes as Base64, and on the way back turn the bytes into text with TextDecoder. The table below shows what that does to the length, which is the part that surprises people.

TextCode pointsUTF-8 bytesBase64
f11Zg==
Hello55SGVsbG8=
café45Y2Fmw6k=
中文265Lit5paH
😀148J+YgA==
Hello 世界 😀 café1523SGVsbG8g5LiW55WMIPCfmIAgY2Fmw6k=

Every row is computed on this page from the value you can see in the table, so you can check any of them by pasting the text into the box above and comparing. The last row is the one worth internalising: 15 characters become 23 bytes, because two Chinese characters cost three bytes each and the emoji costs four. Base64 encodes bytes, so the output is longer than the text — and if you are budgeting for a URL or a header value, the number you need is the byte count, not the character count. The tool prints both.

Standard and URL-safe: the same bytes, two alphabets

Base64 needs 64 characters and the base alphabet supplies 62 free: A–Z, a–z and 0–9. The last two have to come from somewhere, and there are two conventional choices. The standard alphabet (RFC 4648, section 4) takes + and /. The URL-safe variant takes - and _ instead, because + means space in a form-encoded body and both + and / have to be escaped inside a URL path or query.

Three consequences that matter in practice:

  • The first 62 characters are identical, so a value that happens to contain neither + nor / encodes to exactly the same string in both. 5Lit5paH is not "standard" or "URL-safe" — it is both.
  • Mixing them is not a third alphabet. A string containing + and - at once is invalid in both, and a tool that silently picks one produces different bytes from a tool that picks the other. This page rejects it and says why.
  • JSON Web Tokens use the URL-safe form. That is the most common place a developer meets - and _ in Base64 without realising it, and also where the missing padding comes from — see the next section.

If you copy a value from a URL or a token and paste it here, the page tells you which alphabet it found. If it contains neither special character, the tool says that too, rather than claiming it detected something it could not have.

Padding: the = signs, and why they are so often missing

Base64 reads the input three bytes at a time and writes four characters for each group. When the input length is not a multiple of three there is a remainder of one or two bytes, and the encoding is finished off with two or one = characters — not as data, but as a statement that the group was short.

That statement is redundant: from the length of the characters before the padding, the remainder can be computed. So some systems keep the = signs (config files, PEM blocks, most command-line tools) and others drop them (JWT, many query strings, some APIs). Both are read correctly here. When the padding is absent the tool adds it back and says how many signs it added, so you are never left wondering whether your input was one character short or deliberately unpadded.

The reverse case is worth knowing because it looks innocent: SGVsbG8== is not a shorter way of writing SGVsbG8=. Seven data characters need exactly one padding character, so two of them is a contradiction — which usually means the value was edited by hand or two values were joined. The tool reports it as a mismatch with both numbers, rather than decoding the part it likes and ignoring the rest.

Why is my Base64 different?

This is the question that brings most people to a page like this one: the string is valid in one place and rejected in another, or two tools give two different strings for what is supposedly the same value. Almost always it is one of the causes below, and every one of them is visible if you look at the bytes instead of the characters. The hex view on this page is there for exactly that.

What you seeWhat actually happenedHow to check it here
The value ends in Cg or Cg== and yours does not One of them has a trailing newline. Editors add one at the end of a file, so "Hello" and the file containing Hello are different inputs. SGVsbG8= is Hello; SGVsbG8K is Hello plus a line feed. Paste both and compare the byte counts and the hex view — the extra byte is 0a.
A long value with line breaks every 76 characters, and your tool rejects it That is the MIME convention for email bodies and PEM files. The breaks are transport formatting and are not part of the data. Paste it as-is. The breaks are removed before decoding, and the count is reported in the notes.
Yours ends in = and theirs does not (or the reverse) One system kept the padding and the other dropped it. Neither is wrong; the padding is derivable from the length. Decode either form. The Padding row tells you which case you had.
Yours contains + or /, theirs contains - or _ One is standard Base64 and the other is URL-safe. Same bytes, different two characters. Both are accepted; the Alphabet detected row names the one it found.
Same text, different length entirely The two sides encoded different encodings of the text. is e4b8ad in UTF-8 but 2d4e in UTF-16LE, and legacy single-byte encodings give a third answer again. Windows tooling and .NET APIs default to UTF-16LE more often than people expect. Decode both and compare the hex views. Letters separated by 00 bytes mean UTF-16.
Your value starts with H4sI Not text at all — it is gzip-compressed data, whose first bytes are 1f 8b. Something compressed the payload before encoding it, and the Base64 is a faithful copy of the compressed stream. The page reports that the bytes are not UTF-8 text and shows the hex, where 1f 8b is visible.
Decoding gives %3D, %2B or %2F where you expect =, +, / The value went through URL encoding after being Base64-encoded, so the three characters that matter in a URL were percent-escaped. Decoding the Base64 first cannot work, because the percent signs are part of what you pasted. Percent-decode the value before pasting it here. The error message names the position of the %.
Yours looks right but the other side says it is invalid Something stripped a character in transit. The usual suspects are a chat client that ate a +, a spreadsheet that reformatted the cell, and a copy that stopped one character early — which leaves a length that no Base64 can have. The error names the position of the bad character, or reports the impossible length with the count.

Two of these are worth stating flatly, because they account for a large share of confused afternoons. The first is the trailing newline: a value pasted from a file usually has one and a value typed by hand does not, and one byte at the end changes the last four Base64 characters. The second is encoding: the same characters encode differently in UTF-8, UTF-16 and every legacy code page, which is why "the same string" can produce two Base64 values that both decode successfully to the same text on their own terms.

When valid Base64 is not text

Base64 is a byte encoding, not a text encoding. It will carry an image, a PDF, a compressed stream, an encrypted value or a TLS certificate just as happily as it carries a sentence, and it has no way to tell you which it is carrying. So there is a case that a decoder has to answer deliberately: the input is correct Base64, it decodes to bytes, and those bytes are not valid UTF-8.

There are only two things a tool can do, and one of them is worse than saying nothing:

  • It can substitute replacement characters. Every byte sequence can be "decoded" this way — invalid bytes become U+FFFD, the black diamond question mark. The result is a string, it looks like output, and it is worthless: the user copies it, pastes it somewhere else, and the corruption is now in two places.
  • It can say the bytes are not text and show what they actually are. That is what this page does: the byte count, the offset of the first byte that breaks the rule, the class of breakage, and a hex view.

The offset and the class are the useful part, because they point at the cause. A break at the very end of the data in the middle of a multi-byte sequence means the value was truncated — the classic "the API cut the response and the last character of a Chinese string is missing". A break at the start, with a byte above 0xf4, means it was never text. Bytes that alternate letter and 00 mean UTF-16, which is legal UTF-8 with NUL characters rather than invalid UTF-8, so this page decodes it successfully and the hex view is where the pattern shows up. And a handful of well-known first bytes tell you the format outright: 1f 8b is gzip, 89 50 4e 47 is a PNG, 25 50 44 46 is a PDF.

Note what this page does not do: it does not guess an encoding for you. Detecting UTF-16, Latin-1 or a legacy code page from the bytes alone is unreliable, and a decoder that guesses wrong produces exactly the wrong text with no warning — the failure mode this whole page is organised against.

What this tool refuses, and why

Every entry below is something a tolerant decoder would accept, because bytes exist that make it "work". None of them says what was meant, so the tool refuses and names the problem instead of returning a value that is quietly different from the one you wanted.

InputWhy it is refusedWhat to do instead
A, or any value whose data length leaves one character overFour Base64 characters hold three bytes, so a single leftover character holds nothing at all. This length cannot come from any byte sequence.Check whether the copy stopped early — a truncated paste is the usual cause
SGVs=bG8=An = in the middle. Padding is only meaningful at the end; one in the middle means the value was joined with something else or edited, and there is no way to tell which part was meant.Take the two values apart and decode them separately
++--It mixes the standard alphabet with the URL-safe one, so it is not valid in either. Choosing one of them silently would give bytes you cannot check.Decide which alphabet the source used and convert the two characters
SGVsbG8==Seven data characters call for one =, not two. The padding and the length disagree, so one of them was changed.Use SGVsbG8=, or drop the padding entirely
==Padding with no data. There are no characters to decode.Check what was actually copied
Zm9v😀, and anything with full-width charactersNot in the alphabet. Emoji and full-width characters look like corruption and are usually the result of pasting into the wrong field.The error reports the character and its position
More than 2,000,000 charactersA single-threaded conversion at that size locks the tab for long enough that the browser offers to kill the page — which looks like the tool having crashed.Split the input and convert the parts

The size limit is a deliberate choice rather than a technical ceiling: the conversion is plain arithmetic and a browser can do it for tens of megabytes if it is allowed to block, but a frozen tab with no output is not a slow result, it is a broken one. Two million characters is roughly a 1.5 MB file after decoding — far beyond the headers, tokens and config values this tool is for, and small enough that the result appears immediately. Above 300,000 characters the page paints a status line before starting, so even the slowest case shows something.

What leaves this page

Nothing. The page is a static file that imports one module of pure functions; the conversion, the UTF-8 handling, the validation and the hex view all run in the tab you already have open. There is no request to our server, no analytics event carrying your value, no cookie and no storage — reload the page and the text is gone, because it was never anywhere else.

That said, this is the worst category of tool to be careless with. Base64 is what an Authorization header is made of, what most session cookies carry, and what an API key looks like when it is written down. A value pasted into a tool that uploads is a credential handed over; a value pasted here stays local, but the clipboard, the browser's own history of that text field and the screen you are sharing on a call are outside this page. Decoding a token to read its claims is ordinary and safe; pasting a live key into anything is not, whatever the tool promises.

Common questions

Is Base64 encryption? Can I use it to hide a password?
No. Base64 is a way of writing bytes using 64 printable characters, and anyone can reverse it in one step — including this page, with no key and nothing to guess. It exists because some channels only carry text: JSON strings, email bodies, URLs, HTTP headers. If you need secrecy, use encryption; if you need to check the value was not corrupted, use a hash. A password that looks like random letters is not protected by being unreadable at a glance, and a token pasted into a public gist is still a live token.
Why is the Base64 of my Chinese text so much longer than the text itself?
Because Base64 encodes bytes, not characters, and the bytes come from UTF-8. One ASCII character is one byte, but a Chinese character is three bytes in UTF-8 and an emoji is four. Every three bytes become four Base64 characters, so a Chinese character costs four characters plus a third, while an ASCII letter costs about one and a third. The tool prints both numbers above the result — code points and UTF-8 bytes — so you can see the ratio instead of guessing at it.
What is the difference between standard Base64 and URL-safe Base64?
Only the last two characters of the alphabet. Standard Base64 uses + and /, which have special meanings in URLs and in some query strings; URL-safe Base64 uses - and _ instead, so the value can be pasted into a URL without escaping. The first 62 characters are identical, so anything that happens to contain no + or / encodes to exactly the same string in both. JSON Web Tokens are the best-known user of the URL-safe form.
Why is the = padding missing from my Base64?
Because the padding carries no information. Base64 works in groups of four characters holding three bytes, and when the input is not a multiple of three the leftover is signalled with one or two = signs. Those signs can be recomputed from the length of the data, so systems that care about compactness — JWTs, query strings, some config formats — drop them. This tool accepts both forms and tells you when it had to add padding back, so you can see what your input actually looked like.
The tool says my Base64 is valid but not UTF-8. What does that mean?
It means your input is correct Base64 — it decodes cleanly to bytes — but those bytes are not text in the UTF-8 encoding that virtually all of the modern web uses. Common causes: the value is an image, a PDF, a gzip stream or an encrypted blob; or it is text in UTF-16 and every other byte is a zero; or the data was cut short, which leaves the multi-byte sequence of a character incomplete at the end. The tool shows the byte count, the offset of the first byte that breaks the rule, and a hex view, because printing replacement characters would hand you a corrupted string that looks like a result.
Is anything I paste here uploaded, logged or stored?
No. The page imports one module of pure functions and runs it in the tab you already have open: there is no request to our server, no analytics event carrying your text, no cookie and no storage of any kind. That matters more for this tool than for most, because Base64 is what authorization headers, session cookies and API keys are made of — a pasted token is often a live credential. Even so, the clipboard, the browser history and the screen you are sharing are outside this page, so treat a live secret as live wherever you paste it.

No data of any kind. This page ships no tables, no sample payloads and no list of character encodings — every byte it shows is computed from what you typed, using the browser's own UTF-8 encoder and decoder and the arithmetic of RFC 4648.