Base64 Encode/Decode: Text, Files and Images Online

Base64 Encode/Decode: Text, Files and Images Online

Encode or decode text, a file, or an image as Base64 in the browser — data URIs, email attachments, JWT segments. 100% local, not encryption.

18.09.2026
14 min read
Share this article:
Base64
Encoding
Data URI
Tutorial

Why Base64 still shows up in every stack

A CSS background that cannot fetch a file, a MIME attachment that must travel as ASCII, a JWT segment sitting between two dots, a WordPress option that was serialized then wrapped in Base64: none of these are encryption problems. They are transport problems. The online Base64 encoder and decoder turns Unicode text into an ASCII-safe alphabet and back, entirely in the tab. The image to Base64 converter does the same for a local PNG, JPEG, GIF, WebP or SVG — as a data URI or as raw Base64. Nothing is uploaded. Base64 is not a hash, not a cipher, and not a substitute for TLS. It is a way to carry bytes through channels that only like letters, digits, +, / and padding. The cluster lives on the encoding tools hub.

UTF-8 round-trip for Unicode text — accents, CJK, emoji — not the broken native btoa path
URL-safe mode (RFC 4648): - and _ instead of + and /, padding omitted — the alphabet JWTs actually use
Decode strips whitespace, so wrapped MIME lines and copied JWT segments still parse
Image tool: PNG, JPEG, GIF, WebP, SVG, 32 MiB, data URI or raw Base64, preview via img only
100% local — the string never leaves the browser
Chain with JWT decode, URL encode, HTML entities, SVG data URI, JSON formatter

When to encode in the browser, and when not to

Good fits

The encoder is a scalpel for a string you can paste, not a CDN.

Reading a JWT header or payload segment, or decoding a wrapped MIME line, without opening a REPL
Building a tiny CSS data URI for an icon you already optimized
Checking that a backend's Base64 matches UTF-8 (café, emoji) instead of a Latin-1 lie
Peeling a Base64 wrapper off a WordPress or Laravel blob before unserialize
Teaching the difference between encoding, hashing, and encryption with an instant round-trip
Leave it to the pipeline

If the answer depends on a file the browser should not hold, or on cryptography, stay in CI or a secret manager.

Production hero images, product photos, or any asset where 33% extra CSS is worse than one HTTP request
Secrets — Base64 does not hide them; use a vault, not an encoder
Password storage — hash (bcrypt/Argon2), never encode
HEIC, PDF, or files above 32 MiB — out of scope for image-to-base64
Verifying a JWT signature against a JWKS — <a href="/en/jwt-verify" class="text-primary hover:underline">jwt-verify</a>, not decode-and-hope

The Base64 mistakes that burn an afternoon

Calling encoding encryption

Anyone who can read the string can decode it. Base64 has no key, no integrity check, and no confidentiality. A token that looks opaque in a log is still plaintext after one decode. If the bytes must stay secret, encrypt (or do not put them in the payload). If they must stay authentic, sign — HMAC or a JWT signature, not Base64 itself.

Shipping an API key as Base64 and calling it "obfuscated"
Storing passwords as Base64 instead of a password hash (bcrypt, Argon2)
Assuming a data URI hides the asset from anyone who views source
Confusing Base64 with SHA-256: a digest is one-way; Base64 is reversible by design
Mixing standard Base64 and Base64URL

RFC 4648 defines two alphabets. Standard Base64 uses + and / and usually keeps = padding. URL-safe Base64 (the JWT, cookie, and path flavour) uses - and _ and typically drops padding. FastMinify's URL-safe toggle does both substitutions and omits padding on encode. Decode in URL-safe mode maps the alphabet back and restores padding. If the toggle does not match the string, you get an invalid-input error — not a "close enough" decode.

Pasting a JWT segment with - and _ while URL-safe is off
Expecting standard mode to accept a string that lost its = padding
Copying a data URI's payload (standard alphabet, with padding) into a JWT field
Hand-replacing + with - in one place and forgetting / → _
Pasting a whole JWT into the text decoder

A compact JWT is three Base64URL segments separated by dots: header.payload.signature. The dots are not Base64. The Base64 tool decodes one alphabet string, not a dotted token. The error copy on the page says so: paste only the encoded characters, no dots; for a JWT, copy each part between the dots — or, simpler, open the JWT decoder and inspect header plus payload in one step.

Pasting eyJhbGciOi… as a single blob including the dots
Decoding the signature segment as UTF-8 text and expecting a readable JSON object
Using jwt-decode when you only have a random Base64 blob with no header.payload.signature shape
Forgetting that jwt-decode reads claims — it is not a replacement for jwt-verify against a JWKS
Inlining a photograph as a data URI in production CSS

Base64 expands binary data by about 33% (3 bytes become 4 ASCII characters). A 200 KiB JPEG becomes ~267 KiB of CSS. That CSS is ineligible for a separate cache, blocks parsing, and fights HTTP/2 multiplexing. Data URIs earn their keep for tiny icons that would otherwise cost a request. They lose for hero images, product photos, and anything you already minify as a file.

Dropping a 2 MiB PNG into image-to-base64 and pasting the result into a stylesheet
Expecting a data URI to compress better than the original file under Brotli — the alphabet is denser, not smaller
Skipping the <a href="/en/blog/svg-optimization-guide-web" class="text-primary hover:underline">SVG optimization guide</a> before inlining an exported SVG
Using the text Base64 tool on a binary image: that tool encodes Unicode text, not file bytes

Standard Base64, URL-safe, data URI — pick the representation

Three outputs, one alphabet family

The bytes do not change. The spelling does. Standard Base64 is what email MIME and most APIs emit. URL-safe Base64 is what JWTs, signed cookies, and path segments need so + and / do not collide with query syntax. A data URI is standard Base64 with a data:&lt;mime&gt;;base64, prefix so a browser can treat the string as a resource.

Standard: A–Z a–z 0–9 + / and = padding — image-to-base64 raw output, most docs, most databases
URL-safe: A–Z a–z 0–9 - _ , padding omitted — toggle on the text tool; JWT header/payload spelling
Data URI: data:image/png;base64,iVBOR… — image-to-base64 default output, CSS url(), img src
The prefix is not Base64. Do not paste data:image/… into the text decoder; strip it or use the image tool
Text tool vs image-to-base64 vs SVG data URI

Three tools, three inputs. The text encoder runs UTF-8 then Base64 on a string (paste or a text file). It will not interpret a PNG as pixels. The image converter reads file bytes, checks MIME (PNG, JPEG, GIF, WebP, SVG — empty MIME is rejected, no silent sniff), caps at 32 MiB, and emits a data URI or raw Base64. Preview uses an img element only: SVG is never injected into the DOM as markup. For SVG-as-CSS with utf-8 or Base64 encoding and a dedicated CSS snippet, use the SVG to data URI tool on the SVG hub (512 KiB SVG input — a different cap, a different job).

Unicode string, JSON blob, JWT segment, config snippet → /base64
Local raster or SVG file you want as data:image/… → /image-to-base64
SVG source you want as a CSS url() with encoding choice → /svg-to-data-uri
Percent-encoding a query value is not Base64 — that is /url-encode
Base64 is not URL-encode, HTML entities, or a hash

Developers mash these together because they all "make a string safer". They solve different collisions. URL encode percent-encodes reserved URI characters. HTML entities escape markup so a string can sit in an attribute. A hash (SHA-256, HMAC) is one-way integrity or authenticity — see the encoding hub's hash/HMAC tools, not this article. Base64 only changes how bytes are written.

Need a string in a query parameter → URL encode, not Base64
Need a string inside HTML without breaking the tag → HTML entities
Need to detect tampering → hash or HMAC, then maybe Base64 the digest for transport
Need ASCII-safe bytes in JSON, email, or a data URI → Base64

What Base64 actually does to your bytes

A 64-character alphabet and a 33% tax

Base64 takes 24 bits (3 bytes) and writes them as 4 characters from a 64-symbol alphabet. That is why the output is longer: 4/3, about 33% more, plus padding if the input length is not a multiple of 3. The tax is the point — you trade size for an alphabet that survives email, JSON strings, and CSS. It is the opposite of minification. If the payload is JSON you will ship over HTTP, minify the JSON first, then encode only if a wrapping layer requires ASCII; see the JSON minification guide.

Before

foo

After

Zm9v
3 input bytes → 4 output characters; 1 leftover byte → 2 characters + ==; 2 leftover bytes → 3 characters + =
The alphabet is ASCII: it survives copy-paste, YAML, and logs that mangle binary
Whitespace in the encoded string is ignored on decode in FastMinify — MIME often wraps at 76 characters
Expansion is on the encoded form. Gzip/Brotli on a data URI inside HTML is not as effective as gzip on the original file
UTF-8 first, then Base64

JavaScript's built-in btoa operates on a binary string (values 0–255). Pass it café and it throws or produces a lie, depending on the engine. FastMinify encodes the UTF-8 bytes with TextEncoder, then Base64 — the same contract as Node Buffer.from(text, 'utf8').toString('base64'). Decoding reverses it with TextDecoder. Emoji and CJK survive. If you decode a blob that was never UTF-8 text (a PNG, a gzip stream), you get replacement characters, not a file — that blob belongs in image-to-base64 or a hex dump, not in a text field.

Before

café

After

Y2Fmw6k=
café → Y2Fmw6k= (UTF-8 for é is two bytes C3 A9)
Hello, 世界 → SGVsbG8sIOS4lueVjA==
Native btoa/atob without a TextEncoder is the classic Unicode footgun — the online tool does not take that path
Binary images: drop the file on image-to-base64; do not paste "binary" into the text encoder
Padding, and why JWT drops it

When the byte length is not a multiple of 3, standard Base64 appends = or == so the string length is a multiple of 4. URL-safe contexts (JWT, some cookies) omit that padding because = is a query delimiter. FastMinify URL-safe encode strips it; URL-safe decode puts it back before atob. Classic RFC examples: fZg==, foZm8=, fooZm9v.

Before

f

After

Zg==
Standard decode: missing padding can fail — paste the = or enable URL-safe if the producer omitted it
URL-safe encode of +/8= becomes -_8 (alphabet swap and padding gone)
A JWT header {"alg":"HS256","typ":"JWT"} encodes to eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 — no padding
Do not add padding to a data URI payload by hand unless you are repairing a truncated copy

Encode in the tab: text, then a file, then an image

Encode or decode a string

Open the Base64 encoder/decoder. Paste the text (or upload a text file — client ceiling 32 MiB, same family cap as other file picks on the site). Choose Encode or Decode. Leave URL-safe off for MIME, data-URI payloads, and most API examples. Turn it on for JWT segments, signed cookie values, and anything that will sit in a path. Load sample if you only want to see the pipeline. Everything stays in the tab.

1

Step 1 — Paste or upload the source

Unicode text for encode; a Base64 alphabet string for decode. Do not include JWT dots or a data: prefix.

2

Step 2 — Set URL-safe to match the producer

On: - _ and no padding. Off: + / and = padding. A mismatch is an error, not a partial decode.

3

Step 3 — Copy the result

If you decoded JSON that was minified, send it to the JSON formatter or the online JSON unminifier — format only, names already lost stay lost.

Turn a local image into a data URI

Open the image to Base64 tool. Drop a PNG, JPEG, GIF, WebP or SVG (max 32 MiB). Choose data URI for CSS url() and img src, or raw Base64 to pipe into another tool. Preview renders through an img element; SVG is not mounted as DOM. Empty or exotic MIME types are rejected — the tool does not guess. After a tiny icon, you can paste the URI into CSS. After a photograph, you usually should not.

Allowed types: image/png, image/jpeg, image/gif, image/webp, image/svg+xml — not PDF, not HEIC in v1
32 MiB hard cap — larger files are refused; there is no unlimited upload
Default output starts with data:&lt;mime&gt;;base64, — raw mode drops the prefix
SVG you still need to optimize first: minify-svg / the SVG optimization guide, then encode
After Base64: JWT, URL, JSON, PHP

Encoding is usually one step in a longer debug. The encoding hub keeps the neighbours one click away.

Compact JWT: decode a JWT (header + payload). Mint a test token with JWT encode — still not verification
Query strings: URL encode / URL decode — percent-encoding, different alphabet
Decoded JSON that is minified: JSON formatter, or minify JSON if you are packing a payload for an API — see also optimizing REST API JSON
WordPress-style blob: Base64 decode, then unserialize PHP if the inner bytes are a PHP serialized array — PHP serialization guide
Hub overview: encoding tools · also on developer utilities

When the browser is enough — and when you still need a REPL

Node Buffer — the same UTF-8 contract

If the string already lives in a script, Node's Buffer matches FastMinify's UTF-8 then Base64 path. Use base64url when the consumer is a JWT library.

Basic example

const { Buffer } = require('node:buffer') const encoded = Buffer.from('café', 'utf8').toString('base64') // Y2Fmw6k= const urlSafe = Buffer.from('café', 'utf8').toString('base64url') // Y2Fmw6k const roundTrip = Buffer.from(encoded, 'base64').toString('utf8') // café
Browser TextEncoder — do not call btoa on Unicode

The native btoa / atob pair is a binary-string API. Wrap it with TextEncoder/TextDecoder, or you will corrupt anything outside Latin-1. That wrap is what the FastMinify text tool already does.

Basic example

const bytes = new TextEncoder().encode('café') let binary = '' bytes.forEach((b) => { binary += String.fromCharCode(b) }) const encoded = btoa(binary) const decodedBytes = Uint8Array.from(atob(encoded), (c) => c.charCodeAt(0)) const text = new TextDecoder().decode(decodedBytes)
openssl for a file on disk

A local PEM, a binary fixture, or a CI job that must not open a browser: openssl stays the right hammer. FastMinify will not replace a pipeline that already hashes or signs files on disk.

Basic example

openssl base64 -in icon.png -out icon.b64 openssl base64 -d -in icon.b64 -out icon.png
FastMinify base64 / image-to-base64

No install, no upload, UTF-8 text plus a dedicated image converter with an honest 32 MiB cap and a URL-safe toggle. Trade-off: the text tool is not a binary file encoder; HEIC/PDF are out of scope for the image tool; JWT verification is a different page. Use it to inspect, teach, and unblock a machine without Node — then keep openssl or Buffer in CI.

Conclusion

Base64 is a boring, essential adapter: bytes in, ASCII-safe alphabet out, 33% larger, fully reversible. FastMinify runs that adapter in the browser — UTF-8 text with an optional URL-safe alphabet, and a separate image converter (PNG, JPEG, GIF, WebP, SVG, 32 MiB) that emits a data URI or raw Base64 without injecting SVG into the DOM. It does not encrypt, it does not hash, and it does not replace jwt-verify or a CDN. Encode the snippet, decode the log line, inline the icon, then stop. Start on the encoding tools hub, and open JWT decode when the string has two dots.

Match URL-safe to the producer — JWT segments on, MIME and data URIs off
Never treat Base64 as encryption or as a password hash
Use image-to-base64 for files; the text tool is Unicode, not pixels
Inline data URIs only when the asset is small enough to pay the 33% tax
Whole JWT → jwt-decode; signature policy → jwt-verify
Share this article
Share this article: