Base64 encoder / decoder

Client-side only. Text is UTF-8 encoded before Base64. Nothing is uploaded.

By Cobra · Last updated

Same string, two alphabets

Base64 turns bytes into ASCII. The classic alphabet uses + and /. URL-safe (RFC 4648 base64url) swaps those for - and _ so the value survives query strings. Same input bytes, different characters:

Input (UTF-8)StandardURL-safe (no pad)
Hi?SGk/SGk_
a+bYStiYSti (no +/ here)
subjects?_dcontains +// when those bytes appearuses -/_ instead
Hello, ToolPetalSGVsbG8sIFRvb2xQZXRhbA==SGVsbG8sIFRvb2xQZXRhbA

Tick URL-safe when the consumer expects base64url (JWTs, many OAuth challenges). Leave it off for classic MIME-style Base64.

Encode path, decode traps

Encode: this page runs TextEncoder (UTF-8), then Base64. Emoji and accented characters are fine; legacy Latin-1-only encoders are not what you get here.

Decode: Base64 first, then TextDecoder with fatal: true. If the bytes are not valid UTF-8 text, you get an error instead of silent garbage. Binary blobs belong in a hex or file tool, not in a text box pretending to be UTF-8.

Padding (=): some APIs strip it. Leave Keep / restore = padding on unless you know the peer wants unpadded strings. On decode, missing padding is restored when the length needs it.

What this page will not do

Base64 and Base64url in code

Encode UTF-8 text with the standard and URL-safe alphabets, then decode it back. The output matches this page.

JavaScript: Buffer (Node) and btoa (browser)

// Node.js: Buffer handles UTF-8 and the URL-safe alphabet
const std = Buffer.from("héllo ✓", "utf8").toString("base64");
const url = Buffer.from("héllo ✓", "utf8").toString("base64url"); // no padding
console.log(std, url, Buffer.from(std, "base64").toString("utf8"));

// Browser: btoa only takes Latin-1, so encode UTF-8 bytes first
const bytes = new TextEncoder().encode("héllo ✓");
const b64 = btoa(String.fromCharCode(...bytes));
const back = new TextDecoder().decode(Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)));
console.log(b64, back);

Python: base64 module

import base64

raw = "héllo ✓".encode("utf-8")
std = base64.b64encode(raw).decode("ascii")
url = base64.urlsafe_b64encode(raw).rstrip(b"=").decode("ascii")
print(std, url)

# Decoding URL-safe input: put the padding back first
padded = url + "=" * (-len(url) % 4)
print(base64.urlsafe_b64decode(padded).decode("utf-8"))

Go: encoding/base64

package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	raw := []byte("héllo ✓")
	std := base64.StdEncoding.EncodeToString(raw)
	url := base64.RawURLEncoding.EncodeToString(raw) // URL-safe, no padding
	fmt.Println(std, url)

	back, err := base64.RawURLEncoding.DecodeString(url)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(back))
}

Each snippet was run on October 14, 2026 with Node.js 20, Python 3.14 and Go 1.24.

Base64 specs: RFC 4648 and docs

FAQ

Does this Base64 tool upload my text?

No. Encoding and decoding run in JavaScript on this page. ToolPetal has no backend for Base64 conversion.

What is the difference between standard Base64 and URL-safe?

Standard Base64 uses + and / and often ends with = padding. URL-safe (base64url) swaps those for - and _ so the string survives query strings and path segments. Toggle URL-safe on this page when you need that alphabet.

Why does decode fail on some strings?

Common causes: wrong alphabet (standard vs URL-safe), missing or extra = padding, whitespace you meant to keep, or bytes that are not valid UTF-8 when decoded as text. This page reports the error instead of inventing output.

Is Unicode handled correctly?

Yes for text mode. Encode runs TextEncoder (UTF-8) before Base64. Decode runs TextDecoder (UTF-8, fatal) after Base64 so invalid byte sequences surface as errors rather than mojibake.