Encode or decode Base64 instantly.
Type or paste any text and get the Base64 output immediately, with no ads, no trackers, nothing sent to any server. Your input is processed entirely in your browser using JavaScript's built-in btoa() and atob() APIs.
How this Base64 tool works
Six steps from the moment you paste to the moment you copy. All of them happen in the page: there is no request, no upload, and no server that ever sees your input.
- 1
You pick a direction
Encode turns plain text into Base64. Decode turns Base64 back into text. The labels above both boxes change with the mode, so you always know which side holds which.
- 2
Your text is UTF-8 encoded first
Before encoding, the input is converted to UTF-8 bytes. This is the step the browser's raw btoa() skips, and it is why btoa() throws on emoji, accented letters, and CJK text while this tool does not.
- 3
Bytes are grouped three at a time
Base64 reads 3 bytes (24 bits) and rewrites them as 4 characters of 6 bits each. When the input does not divide evenly by three, the last group is padded with one or two = characters so the output length stays a multiple of four.
- 4
URL-safe mode rewrites two characters
With the toggle on, + becomes - and / becomes _ after encoding, and the trailing = padding is stripped. That is the base64url variant used by JWTs and OAuth, and it survives being dropped straight into a query string.
- 5
Decoding normalises before it decodes
In Decode mode the input is trimmed, - and _ are mapped back to + and /, and any missing padding is restored. A JWT segment therefore decodes correctly without you touching the URL-safe toggle, which only affects encoding.
- 6
Output is measured, copied, or swapped back
Under each box you get a character count and a UTF-8 byte size, so the roughly 33 percent growth is visible. Copy puts the result on the clipboard, and Swap feeds the output back in as the new input with the mode flipped, which is the fastest way to verify a round trip.
What the output tells you
Base64 output is not opaque once you know what to look at. The alphabet, the padding, and the length all carry information about the input.
Only the 64 characters A-Z, a-z, 0-9, + and / appear, plus = as padding. Seeing + or / in a token tells you it is standard Base64, and that it must be percent-encoded before it goes into a URL.
Input Hello, World!
Output SGVsbG8sIFdvcmxkIQ==Padding tells you how many bytes the final group was short of three. No = means the input length divided evenly by three, one = means the last group held two bytes, two = means it held one. It is never part of the data.
"Man" -> TWFu (3 bytes, no padding)
"Ma" -> TWE= (2 bytes, one pad)
"M" -> TQ== (1 byte, two pads)The URL-safe toggle produces this variant. It is what you see in JWT segments and OAuth state parameters. Decoders that only accept standard Base64 will reject it, which is the usual cause of a token that works in one library and fails in another.
Standard a+b/c==
URL-safe a-b_c
JWT header.payload.signature segments are all base64urlIn Decode mode this appears when the string cannot be decoded. The usual causes are a character outside the alphabet (a stray quote, a space in the middle of a copied token), a truncated string, or accidentally pasting plain text while still in Decode mode.
SGVsbG8sIFdvcmxkIQ= <- truncated padding
SGVsbG8s IFdvcmxkIQ== <- copied with a line break
Hello, World! <- plain text, wrong modeEvery 3 bytes in become 4 characters out, so encoded output is about 33 percent larger than the source. The exact output length is 4 times the input byte count rounded up to the next multiple of 3, divided by 3. For a 1 MB image that is roughly 1.37 MB of text.
Formula: outputChars = 4 * ceil(inputBytes / 3)
12 bytes -> 16 chars
100 bytes -> 136 chars
1024 bytes -> 1368 charsBase64 format reference
The alphabet, the padding rules, and the wrappers you will meet in real payloads. Everything here is what the tool accepts on the input side.
Index 0-25 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Index 26-51 a b c d e f g h i j k l m n o p q r s t u v w x y z
Index 52-61 0 1 2 3 4 5 6 7 8 9
Index 62-63 + / (standard)
Index 62-63 - _ (URL-safe / base64url)
Padding = (standard only, stripped in URL-safe)Text M a n
ASCII 77 97 110
Bits 01001101 01100001 01101110
Regrouped 010011 010110 000101 101110
Index 19 22 5 46
Base64 T W F u
3 bytes in, 4 characters out.# Standard, fully padded
SGVsbG8sIFdvcmxkIQ==
# URL-safe, unpadded (padding is restored automatically)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
# Leading and trailing whitespace is trimmed
SGVsbG8=
# Mixed alphabets: - and _ are mapped back to + and /
a-b_cQ==# Data URI: paste only what follows the comma
data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...
^ start here
# JWT: paste one segment at a time, without the dots
eyJhbGci....eyJzdWIi....SflKxwRJ
^ the payload is the middle segment
# PEM: drop the BEGIN and END lines, then join the body into one line
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEAgAAuTANBg...
-----END CERTIFICATE-----
# HTTP Basic: the header value is base64("user:password")
Authorization: Basic dXNlcjpwYXNzd29yZA==One edge case worth knowing: MIME wraps long Base64 at 76 characters per line. Join those lines into a single string before decoding, because padding is recalculated from the length of what you paste.
When developers use Base64
| Use case | Mode |
|---|---|
| HTTP Basic Auth | Encode |
| JWT payload inspection | Decode |
| CSS data URIs | Encode |
| Env var secrets | Encode |
| API response data | Decode |
| URL-safe tokens | URL-safe |
Standard Base64 vs URL-safe Base64
| Standard Base64 | URL-safe Base64 | |
|---|---|---|
| Characters | A–Z, a–z, 0–9, +, / | A–Z, a–z, 0–9, -, _ |
| Padding | = (included) | Stripped |
| Safe in URLs? | No (+ and / need escaping) | Yes (no escaping needed) |
| Use for | Email, CSS data URIs, HTTP Basic Auth | JWT tokens, OAuth tokens, URL params |
Working with Base64 in JavaScript
Copy-paste patterns for the most common scenarios.
// Encode
const encoded = btoa("Hello, World!");
// Decode
const decoded = atob(encoded); // "Hello, World!"// Encode Unicode safely
const encoded = btoa(unescape(encodeURIComponent("Hello 🌍")));
// Decode
const decoded = decodeURIComponent(escape(atob(encoded)));// Encode
const encoded = Buffer.from("Hello, World!").toString("base64");
// Decode
const decoded = Buffer.from(encoded, "base64").toString("utf-8");// Encode URL-safe
const encoded = btoa(unescape(encodeURIComponent(str)))
.replace(/+/g, "-").replace(///g, "_").replace(/=/g, "");
// Decode URL-safe
const padded = str.replace(/-/g, "+").replace(/_/g, "/")
+ "=".repeat((4 - str.length % 4) % 4);
const decoded = decodeURIComponent(escape(atob(padded)));Frequently Asked Questions
What is Base64 encoding?
Base64 converts binary data into a string of printable ASCII characters using a 64-character alphabet (A-Z, a-z, 0-9, +, /, =).
- Why it exists: binary data breaks in text-only contexts (HTTP headers, email bodies, URL parameters, JSON values). Base64 makes any payload text-safe.
- What it is not: Base64 is not encryption and not compression. Encoded output is ~33% larger than the original input.
- Anyone can decode it: Base64 is fully reversible with no key. Never use it as a security mechanism.
Does Base64 encoding encrypt my data?
No. Base64 is encoding, not encryption. Anyone who sees a Base64 string can decode it immediately: there is no key involved.
What is URL-safe Base64 and when should I use it?
| Standard Base64 | URL-safe Base64 | |
|---|---|---|
| Characters | A–Z, a–z, 0–9, +, / | A–Z, a–z, 0–9, -, _ |
| Padding | = (included) | Stripped |
| Safe in URLs? | No (+ and / need escaping) | Yes |
| Use for | Email, CSS data URIs, HTTP Basic Auth | JWT tokens, OAuth tokens, URL params |
Toggle URL-safe mode in this tool when working with JWT payloads or encoding values that will appear in a URL.
How do I decode a JWT token's payload with this tool?
A JWT has three Base64 URL-encoded segments separated by dots: header.payload.signature.
- Copy the payload: the middle segment between the two
.dots. - Switch to Decode mode: the tool auto-detects URL-safe characters (
-and_) and normalises them automatically. - Paste the segment: the decoded JSON object appears immediately.
Why does btoa() throw an error on some strings in JavaScript?
The browser's native btoa() only accepts Latin-1 (ISO-8859-1) characters. Any input outside that range (emoji, accented letters, CJK characters) throws DOMException: The string to be encoded contains characters outside of the Latin1 range.
Fix: UTF-8 encode the string first:
// Encode Unicode safely
const encoded = btoa(unescape(encodeURIComponent(str)));
// Decode
const decoded = decodeURIComponent(escape(atob(encoded)));Why does my Base64 string end in = or ==, and can I remove it?
The = characters are padding. Base64 encodes three input bytes as four output characters, so when the input length is not a multiple of three the encoder pads the final group to keep the output a multiple of four.
One = means the last group held two bytes, two = means it held one byte. Padding carries no data, which is why the base64url variant used by JWTs drops it entirely.
| Input | Input bytes | Output | Padding |
|---|---|---|---|
| Man | 3 | TWFu | none |
| Ma | 2 | TWE= | one = |
| M | 1 | TQ== | two = |
You can strip padding as long as the decoder restores it. This tool does that automatically: paste an unpadded string in Decode mode and it re-adds the = characters before decoding. Stricter decoders in other languages will throw instead, so keep the padding when you are not sure what will read the value.
Should I Base64 encode images or large files?
Rarely. Encoding inflates the payload by roughly 33 percent, and an inlined asset cannot be cached separately, so every page load ships it again.
- Reasonable: tiny assets under a few KB where the saved request matters, such as an icon in a CSS
background-imageor an email signature logo. - Reasonable: APIs that must carry binary inside JSON, since JSON has no binary type.
- Avoid: photos, fonts, and anything over about 10 KB. Serve them as files so the browser and your CDN can cache and compress them.
- Avoid: storing large Base64 blobs in a database column when a file store plus a URL would do.