Skip to content
ansezz.

▸ Free tool

Base64 Encoder / Decoder.

Encode and decode base64 without the UTF-8 bugs — emoji and accents round-trip correctly. base64url and file-to-data-URI included. Nothing leaves your browser.

▸ Encoding, not encryption

Base64 has no key. Anyone who can read the string can read the bytes. Never use it to "hide" a secret.

Try

Type in either box — the direction follows you. Decoding accepts both alphabets.

0 characters · 0 bytes UTF-8

0 characters

File → data URI

Pick a local file and get a complete data: URI you can paste into HTML or CSS. The file is read with FileReader in this tab — it is never uploaded.

No file selected.

What base64 actually does

Base64 takes arbitrary bytes and re-spells them using 64 characters that survive any channel that treats data as text. Three bytes — 24 bits — go in, four 6-bit groups come out, each mapped to A–Z a–z 0–9 + /. When the input is not a multiple of three, the tail is padded with = so the decoder knows where the real bytes stop.

That is the whole trick, and it exists because large parts of the internet are still text-only by contract. SMTP was defined for 7-bit ASCII. HTTP header values cannot carry raw bytes. JSON strings cannot hold a null byte. Base64 buys you a channel-safe representation at a fixed, predictable cost.

The 33% tax

Four characters per three bytes means base64 output is always 4/3 the input size — a flat 33% increase, plus up to two padding characters. A 3 MB image becomes 4 MB of text. Three places where that bill lands and people are surprised:

  • Over the wire. Gzip and brotli claw some of it back for text, but base64 of already-compressed data — JPEG, PNG, WebP, zip — compresses badly, so you eat most of the 33%.
  • In a database. A text column full of base64 blobs is a third larger on disk, in every index that touches it, and in every backup you keep.
  • In an LLM prompt. Base64 tokenizes terribly — a high-entropy character soup fragments into far more tokens than the underlying bytes would suggest. Paste some into the token counter and watch.

Base64 is encoding, not encryption

This has to be said plainly because a surprising amount of production code gets it wrong. Base64 has no key, no secret, and no integrity guarantee. The Authorization: Basic header is nothing but base64 of username:password — that is exactly why Basic auth is only acceptable over TLS. A JWT payload is base64url too, which is why you can read anyone's claims in the JWT decoder without a key. Encoding hides nothing from anyone who has the string. If you need secrecy, encrypt, then base64 the ciphertext for transport.

base64url, and where it is required

+ and / are hostile in URLs: a + decodes back to a space in form-encoded query strings, and a / splits a path segment. RFC 4648 §5 defines base64url, which swaps them for - and _ and usually drops the = padding, since padding has to be percent-encoded as %3D. All three JWT segments use it, as do JWK, WebAuthn, and OAuth PKCE code challenges.

  Standard base64 base64url
Spec RFC 4648 §4 RFC 4648 §5
Character 62 + -
Character 63 / _
Padding = required usually stripped
Safe in a URL
Safe in a filename
Where you meet it MIME, data URIs, Basic auth JWT, JWK, WebAuthn, OAuth PKCE

Decoding here normalises - and _ back to + and / and re-adds padding, so you can paste either flavour without thinking about it. The toggle only controls what comes out.

Data URIs vs a second request

A data: URI embeds the asset in the document that references it. You save a round trip; you pay for it in cacheability. Those bytes cannot be cached independently, cannot be served from a CDN edge, cannot be revalidated with an ETag, and are re-downloaded with every copy of the HTML or CSS that carries them — and they are 33% bigger while doing it. The trade only pays off for small, stable, render-blocking assets: a 1 KB SVG icon, a tiny placeholder, a background pattern. Everything else belongs in a separate file behind a long cache lifetime, which is the whole argument in CDN vs cache. That is why the file panel above starts warning at 100 KB.

Why UTF-8 breaks naive encoders

Most half-broken base64 tools call btoa() on the raw string. btoa() is a Latin-1 function: it only accepts code units up to U+00FF. Give it 🚀 and it throws InvalidCharacterError. Give it é and it does something worse — it quietly emits the single byte 0xE9, which is Latin-1, not the UTF-8 pair C3 A9, so the string decodes to mojibake somewhere downstream.

This tool runs every string through TextEncoder first, so é becomes C3 A9 and 🚀 becomes F0 9F 9A 80 before base64 ever sees them. Decoding reverses it — atob to a byte array, then TextDecoder in fatal mode — so a payload that is not valid UTF-8 raises a real error instead of handing you a string full of replacement characters. Try the Unicode sample button and round-trip it both ways.

Questions, answered

Is base64 encryption?

No. Base64 is a reversible encoding with no key — anyone holding the string can decode it, including this page. It exists to move bytes through text-only channels, not to hide them. If you need secrecy, encrypt the data first and treat base64 as the envelope around the ciphertext.

Why does btoa() throw InvalidCharacterError?

Because btoa() is a Latin-1 function: it only accepts code units from U+0000 to U+00FF, so emoji, CJK, and most non-Latin scripts throw. Worse, characters between U+0080 and U+00FF do not throw — é gets encoded as the single byte 0xE9 instead of the UTF-8 pair C3 A9, which decodes to garbage later. The fix is to run the string through TextEncoder first, which is what this tool does.

How much bigger does base64 make a file?

Exactly one third bigger, plus padding: every 3 bytes become 4 characters, so the output length is 4 × ceil(n / 3). A 100 KB image becomes roughly 133 KB of text, and a data URI adds the data:<mime>;base64, prefix on top. Compression claws some of it back for text, and almost none of it back for already-compressed images.

What is the difference between base64 and base64url?

The encoding is identical; only the last two characters of the alphabet change. Standard base64 uses + and /, while base64url uses - and _ and usually drops the = padding, which makes it safe in URLs, query strings, and filenames. JWTs, JWKs, WebAuthn, and OAuth PKCE all use base64url. This tool lets you pick the alphabet on the way out, and accepts either one on the way in.

Does this base64 encoder upload my data?

No. Encoding, decoding, and the file-to-data-URI conversion all run in your browser using TextEncoder, btoa, atob, and FileReader. There is no request and no server involved — open the network tab and watch it stay empty, or load the page once and then go offline.

Can I base64 encode an image or a PDF here?

Yes. Use the file panel — it reads the file with FileReader and returns a complete data: URI you can paste straight into HTML or CSS, without uploading anything. Watch the size warning: past about 100 KB, an inline data URI usually costs more in lost caching than it saves in round trips.

Keep reading