Base64 Tool Kits runs entirely in your browser

The Base64 tool that never uploads your data

Encode and decode entirely in this tab. Nothing is uploaded, because the page ships a policy that forbids it from making any network request at all once it has loaded.

Base64 converter

Type or paste some text and its Base64 appears here.

Encoding options

How text becomes bytes, and bytes become text, on either side of the Base64. The two directions are not symmetrical and the list says so: browsers can decode around forty character sets, but they can only encode UTF-8 and the single-byte legacy sets, because the platform's encoder produces UTF-8 and nothing else. Multi-byte sets such as Shift_JIS, GB18030, Big5 and EUC-JP are therefore listed as decode-only rather than quietly given UTF-8 bytes under the wrong name.

Uses - and _ where standard Base64 uses + and /, so the result survives a URL, a query string or a filename. Applied both ways: with this on, decoding expects that alphabet and says so if it meets a + or / instead.

Rounds the output up to a whole multiple of four characters with trailing = signs. JWT segments and many URL payloads leave them off; turn this off to match. Decoding accepts input with or without them either way.

Breaks a long Base64 result into fixed-width lines. 76 is what email MIME bodies use; 64 is what PEM keys and certificates use. Line breaks are ignored when decoding, so wrapping never changes what the data means.

Which characters separate the output's lines. LF is one byte, CRLF is two, so this changes the size of a wrapped result as well as where it will paste cleanly. The pane below always displays plain LF — that is a browser rule about text boxes, not our choice — but Copy and Download carry the CRLF, and the character count is of the real result.

Treats every line of the input as its own value, in both directions, so line three in becomes line three out — paste a column of tokens and get a column of answers back. Line wrapping switches off while this is on, because that is the only way each input line can stay exactly one output line.

Base64, explained

What it actually is

Base64 writes arbitrary bytes using 64 characters that survive being treated as text. Computers move bytes around constantly, but many of the channels they move through — a URL, an email body, a JSON string, an HTTP header — were designed for text, and will mangle, strip or reject anything that does not look like it. Base64 sidesteps that by not sending the bytes at all. It sends a spelling of them.

The alphabet is A-Z, a-z, 0-9 and two more characters: 64 in total. 64 is 26, so each character carries exactly six bits. Bytes are eight bits, and six and eight first agree at 24 — which is why the unit of Base64 is three bytes in, four characters out. That ratio is the whole idea. Everything else on this page is bookkeeping around it.

It is a spelling, not a secret. Base64 is specified in RFC 4648, it takes no key, and anything encoded with it can be decoded by anyone — including by the box at the top of this page.

Why the output is about a third bigger

Four characters for every three bytes is four divided by three, so Base64 output runs at 133.3% of its input — a third larger. Encode 300 bytes in the tool above and you get 400 characters back, every time. Two things add a little on top of that:

The practical consequence is that Base64 is never a way to make something smaller. If size matters, compress the bytes first and encode the compressed result — in that order. Compressing the Base64 text instead recovers measurably less, because encoding has already scattered the byte patterns a compressor was looking for.

A worked example, byte by byte

Take the three characters Hi!. In UTF-8 they are three bytes, and three bytes is exactly one Base64 group:

Hi! becomes SGkh: 24 bits, re-cut from three groups of eight into four groups of six.
Character H i !
Byte 0x48 0x69 0x21
Bits, eight at a time 01001000 01101001 00100001
Bits, six at a time 010010 000110 100100 100001
As a number 18 6 36 33
That position in the alphabet S G k h

Paste Hi! into the input above and SGkh is what comes back, because that box runs this arithmetic and nothing else.

Now take a character away. Hi is two bytes — sixteen bits — which is two whole six-bit groups with four bits spare. The spare bits are filled out with zeros to make a third character, and one = is appended to record that the group was one byte short: SGk=. A single H is eight bits, so two characters and two =: SA==.

What the = is for

= carries no data at all. It exists so a decoder reading a stream can tell where the data ended and how much the final group held: no = means a full three bytes, one = means two, two = means one.

When the length is already known some other way — a JSON field, a URL path segment, a database column — padding is redundant, and RFC 4648 allows leaving it off. JWT segments do exactly that. The Add = padding switch above controls only what this tool writes; decoding here accepts input with or without padding either way.

What it will not accept is padding that contradicts itself — a third =, data after the padding has started, or a padded length that is not a multiple of four. Each of those is reported as its own named failure at the index of the character that caused it, rather than being quietly trimmed away.

Standard, URL-safe, MIME, PEM, JWT — and how to tell them apart

The variants you are likely to meet, and what actually differs.
Where you meet it Characters 62 and 63 Padding Lines
RFC 4648 section 4, plain Base64 + / yes one long line
RFC 4648 section 5, base64url - _ optional one long line
Email bodies (MIME) + / yes 76 columns, CRLF
PEM keys and certificates + / yes 64 columns
JWT segments - _ omitted one long line

Only two of the 64 characters differ between the standard alphabet and the URL-safe one — the two that stand for the values 62 and 63. The other 62 are identical, which means a short string is very often valid in both and identical in both. The JSON header {"alg":"HS256","typ":"JWT"} that opens almost every JWT encodes to eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 — 36 characters, no padding needed, and not a +, /, - or _ among them. That string is both variants at once. This is precisely why the two get confused: the difference only appears on some inputs, and usually not on the ones you tested with.

So the honest way to identify a string is to look for evidence, and to accept that there may be none:

This tool takes that seriously rather than guessing. Left alone it reads either alphabet; if one string contains characters from both, it refuses and names the index of each, because picking one would silently produce wrong bytes. Switch URL-safe alphabet on and you are asserting a variant, so a + or / then becomes a named error instead of being quietly accepted.

Every option above, in longer form

Each control carries its own explanation beside it. This is the longer version: when you would reach for it, and what goes wrong if you get it wrong.

Character set
Base64 carries bytes, so something has to decide how your text becomes bytes on the way in and how bytes become text on the way out. That decision is a character set, and the two directions are not symmetrical. Your browser can decode the whole set of encodings in the WHATWG standard, because TextDecoder implements all of them. It can only encode UTF-8 and the single-byte legacy sets, because TextEncoder is defined to produce UTF-8 and nothing else — there is no legacy encoder in the platform, and by design there will not be one. So the multi-byte sets are listed here as decode-only rather than being handed UTF-8 bytes under someone else's name, which would be wrong output presented as right. The list itself is built by asking your browser what it has, not from a table typed into this page.
URL-safe alphabet
Swaps the two characters that break things: + and / become - and _. Reach for it whenever the result has to survive a query string, a path segment, a filename or a cookie value, where / is a separator and + has historically meant a space. It applies in both directions — with it on, decoding expects that alphabet and complains if it meets the other.
Add = padding
Controls whether the output is rounded up to a whole multiple of four with trailing =. Turn it off to match JWT segments and most URL-embedded payloads. It changes nothing about decoding, which accepts either.
Line wrapping
Breaks the result into fixed-width lines: 76 for email MIME bodies, 64 for PEM keys and certificates. Wrapping is cosmetic — this tool ignores line breaks when decoding, so a wrapped and an unwrapped copy of the same data decode to the same bytes. It is not free, though: see the size arithmetic above.
Line endings
Whether wrapped output uses LF or CRLF. It matters more than it looks: CRLF is two bytes to LF's one, so it changes the size of the result, and MIME and PEM both specify CRLF. The output pane always displays plain LF because browsers normalise line endings inside text boxes, but Copy and Download carry the real characters and the character count is of the real result.
Convert each line separately
Treats every line of the input as its own value, in both directions, so line three in becomes line three out. Paste a column of tokens and get a column of answers back. Line wrapping switches itself off while this is on, because that is the only way one input line can stay exactly one output line.

When Base64 is the wrong answer

This is the part most explainers leave out, and it is where the real misunderstandings are. Base64 is a spelling of bytes. It is only that.

Where you actually meet it

What this page does with your text

Everything above runs in this tab. The conversion is JavaScript in your browser, and there is no server side to this tool — no account, no upload, no queue.

That is enforced rather than promised. The site ships a Content-Security-Policy containing connect-src 'none', which means the page is not permitted to make a network request of any kind once it has loaded: no fetch, no background request, no socket, no beacon. And your text cannot reach the address bar either. This page can put exactly eight things in the URL — dir, live, url, pad, wrap, eol, lines and cs — and every one of them is the name of a setting. A test pins that list, so a link you share carries your options and never your data.

The only ways anything leaves this page are the ones you ask for: Copy puts the result on your clipboard, Download writes it to your disk, and — only when decoded output is itself valid JSON — "Open in Json Web Viewer" hands that text to the flagship editor, never through the URL. The only things kept between visits are your theme, your accent and the live-conversion switch, in this browser's local storage. There are no cookies and no analytics.

Still on the way

Text encode and decode work now, with a character-set control that says plainly which sets this browser can write as well as read, and with the URL-safe, padding, wrapping, line-ending and per-line options above — and a bad character is named, given its line and column, highlighted where you pasted it, and offered a fix that has already been checked against your input. Files are next: encoding and decoding whole files, drag and drop, and a preview for images — each one running locally, on this page, with nothing transmitted anywhere.

The same team's JSON tools are live at jsonwebviewer.com, including a JWT decoder built on the same never-leaves-your-browser rule. Decode something whose result is JSON above and an "Open in Json Web Viewer" button appears next to Copy and Download — see the Privacy page for exactly how that handoff works and what it does and does not store.