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:
Base64EncodingData URITutorial

Why Base64 still shows up in every stack

A CSS background image that cannot load a separate 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 file, 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 accept letters, digits, +, / and padding. These tools sit together on the encoding tools hub.

UTF-8 round trip for Unicode text (accents, CJK, emoji), instead of the native btoa path, which corrupts or rejects it
URL-safe mode (RFC 4648): hyphen and underscore instead of plus and slash, padding omitted, as used by JWTs
Decode strips whitespace, so wrapped MIME lines and copied JWT segments still parse
Image tool: PNG, JPEG, GIF, WebP and SVG up to 32 MiB, as a data URI or raw Base64, with a preview rendered through an img element
Everything runs locally: the string never leaves the browser
Chain with JWT decode, URL encode, HTML entities, SVG data URI and 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 Latin-1 bytes
Peeling a Base64 wrapper off a WordPress or Laravel blob before unserialize
Teaching the difference between encoding, hashing and encryption with a round trip in the same tab
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, so use a vault, not an encoder
Password storage: use a hash (bcrypt or Argon2), never an encoding
HEIC, PDF or files above 32 MiB are out of scope for image-to-base64
Verifying a JWT signature against a JWKS: use jwt-verify, 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 them (or keep them out of the payload). If they must stay authentic, sign them with an HMAC or a JWT signature, not with 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
Treat Base64 as wrapping paper. Decode it when you need the bytes; never treat the wrapper as a lock.
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 flavor) uses - and _ and typically drops padding. FastMinify's URL-safe option does both substitutions and omits padding on encode. On decode, URL-safe mode maps the alphabet back and restores the padding, while standard mode passes the string to atob unchanged: atob tolerates missing padding but rejects - and _. A URL-safe string with the option off is therefore an invalid-input error, and a standard string with the option on is still decoded, because those two characters are the only ones that get mapped.

Pasting a JWT segment with hyphens and underscores while URL-safe is off
Trusting a decoding that succeeded on a truncated copy: a missing = is tolerated, so a cut-off string can decode into shorter text
Copying a data URI's payload (standard alphabet, with padding) into a JWT field
Replacing + with a hyphen by hand in one place and forgetting to replace / with an underscore
When the decoder rejects a string that contains hyphens or underscores, switch URL-safe on. Leave it off for MIME, PEM-adjacent blobs and most data URIs.
Pasting a whole JWT into the text decoder

A compact JWT is three Base64URL segments separated by dots, written header.payload.signature. The dots are not Base64. The Base64 tool decodes one alphabet string, not a dotted token. Its error message says so: paste only the encoded characters, with no dots. For a JWT, copy each part between the dots, or open the JWT decoder and inspect header and 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 and is not a replacement for jwt-verify against a JWKS
Whole JWT → jwt-decode. One segment or an arbitrary string → Base64. Signature verification → jwt-verify, not this guide's tools.
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 about 267 KiB of CSS. The image can then no longer be cached separately from the stylesheet, and it makes a stylesheet that already blocks rendering heavier. Over HTTP/2, extra requests are cheap, which removes the main reason to inline. 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 Brotli to cancel the 33% growth: the text compresses, but only back to about the size of the original file
Skipping the SVG optimization guide before inlining an exported SVG
Using the text Base64 tool on a binary image: that tool encodes Unicode text, not file bytes
Convert the image in the tab to see the URI. Ship it only when the asset is small enough that one extra request would cost more than the 33% overhead.

Choose between standard Base64, URL-safe and data URI

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 that + and / do not collide with query syntax. A data URI is standard Base64 with a data:<mime>;base64, prefix, so that a browser can treat the string as a resource.

Standard: A–Z a–z 0–9 + / and = padding, used by the raw output of image-to-base64, most docs and most databases
URL-safe: A–Z a–z 0–9, hyphen and underscore, padding omitted. It is an option of the text tool and the spelling of JWT headers and payloads
Data URI: data:image/png;base64,iVBOR…, the default output of image-to-base64, for CSS url() and 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 and then Base64 on a string, pasted or read from a text file. It will not interpret a PNG as pixels. The image converter reads file bytes and checks the MIME type. PNG, JPEG, GIF, WebP and SVG are accepted, and an empty MIME type is rejected rather than sniffed. It caps files at 32 MiB and emits a data URI or raw Base64. The preview uses an img element only: SVG is never injected into the DOM as markup. For SVG as CSS, with a choice between utf-8 and Base64 and a dedicated CSS snippet, use the SVG to data URI tool on the SVG hub. Its SVG input is capped at 512 KiB, a different limit for 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 that a string can sit in an attribute. A hash (SHA-256, HMAC) provides one-way integrity or authenticity; see the hash and HMAC tools on the encoding hub, 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 33% overhead

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 overhead is the price of an alphabet that survives email, JSON strings and CSS. It is the opposite of minification. If the payload is JSON that 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 lines 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 silently encodes the single Latin-1 byte for é instead of the two UTF-8 bytes; pass it an emoji or a CJK character, and it throws. FastMinify encodes the UTF-8 bytes with TextEncoder and 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 trap; 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 that 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. Standard decode does not need it, because atob tolerates missing padding. Classic RFC examples: f → Zg==, fo → Zm8=, foo → Zm9v.

Before

f

After

Zg==
Standard decode tolerates missing padding, but rejects a string that is one character longer than a multiple of 4
The two bytes FB FF give +/8= in standard Base64 and -_8 in URL-safe Base64, with the alphabet swapped and the padding dropped
A JWT header {"alg":"HS256","typ":"JWT"} encodes to eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 with no padding
Do not add padding to a data URI payload by hand unless you are repairing a truncated copy

Encode text, a file or an image in the tab

Encode or decode a string

Open the Base64 encoder/decoder. Paste the text, or select a text file (the client limit is 32 MiB, like the other file pickers 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 how it works. Everything stays in the tab.

1

1. Paste or select the source

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

2

2. Set URL-safe to match where the string came from

With URL-safe on, the output uses a hyphen and an underscore and has no padding. With it off, the output uses plus and slash and keeps the = padding. A URL-safe string decoded with the option off is an error, not a partial decode.

3

3. Copy the result

If you decoded minified JSON, send it to the JSON formatter or the online JSON unminifier. They only change the layout, so names that were already lost stay lost.

Turn a local image into a data URI

Open the image to Base64 tool. Choose an image (PNG, JPEG, GIF, WebP or SVG, up to 32 MiB) or drop it onto the page. Choose Data URI for CSS url() and img src, or Raw Base64 to pass to another tool. The preview renders through an img element, and SVG is not mounted as DOM. Empty or unsupported MIME types are rejected because 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 and image/svg+xml; PDF and HEIC are not supported
Hard limit of 32 MiB: larger files are refused
The default output starts with a prefix such as data:image/png;base64, and raw mode drops it
SVG you still need to optimize first: minify-svg / the SVG optimization guide, then encode
JWT, URL, JSON and PHP after Base64

Encoding is usually one step in a longer debugging session. The encoding hub groups the neighboring tools.

Compact JWT: decode a JWT (header and payload). Mint a test token with JWT encode, which is still not verification
Query strings: URL encode / URL decode use percent-encoding, a 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 serialized PHP array; see the 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 with 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 instead of btoa on Unicode text

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 tool. 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, nothing uploaded, UTF-8 text plus a dedicated image converter with a 32 MiB cap and a URL-safe option. The limits: the text tool is not a binary file encoder, HEIC and PDF are out of scope for the image tool, and 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, an ASCII-safe alphabet out, 33% larger and fully reversible. FastMinify runs that adapter in the browser. It encodes UTF-8 text with an optional URL-safe alphabet, and a separate image converter (PNG, JPEG, GIF, WebP, SVG, 32 MiB) 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 where the string came from: on for JWT segments, off for MIME and data URIs
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 absorb the 33% overhead
Whole JWT → jwt-decode; signature policy → jwt-verify
Share this article
Share this article: