ScreenshotNeo

BlogEngineering

What Is a Base64 URL? Base64url Explained

Base64url is a URL-safe encoding, not encryption. Learn its alphabet, padding rules, validation, security limits, and working code examples.

By the ScreenshotNeo team1 October 20267 min read

Base64 URL usually means base64url, the URL- and filename-safe variant of Base64 defined in RFC 4648 section 5. It encodes bytes as printable text, changes + to - and / to _, and may omit trailing = padding when the protocol can infer the original length.

Base64url is reversible encoding, not encryption. Anyone who obtains the string can decode it.

1. Base64url at a glance

Question Answer
What is it? A URL- and filename-safe Base64 alphabet.
Which characters change? + becomes -; / becomes _.
What is =? Padding that completes the final four-character group.
Can padding be removed? Only when the protocol says it can be inferred.
Does it protect secrets? No. It provides no confidentiality.

Standard Base64 represents each group of 24 input bits with four characters from a 64-character alphabet. Each output character carries 6 bits. The URL-safe profile keeps the same bit mapping and changes only alphabet positions 62 and 63.

2. Standard Base64 versus base64url

Property Standard Base64 Base64url
Position 62 + -
Position 63 / _
Padding Usually includes trailing = Often omits trailing = when the profile permits
Typical use General binary-to-text transport, MIME, data URLs URL paths, query values, filenames, compact identifiers and tokens

The two encodings are related but should not be treated as interchangeable. A decoder must use the alphabet and padding policy required by the surrounding protocol. For example, a data URL can use standard Base64 because the value is not being used as a path segment or query parameter; MDN documents this distinction in its Base64 glossary.

3. Why the characters and padding matter

In a URL, + may be interpreted as a space by form-style query parsers, and / has path semantics. Base64url avoids both characters. An equals sign is legal in many URL contexts but commonly needs percent-encoding, so URL-oriented profiles frequently remove it.

Padding is determined by the number of input bytes:

  • Input length divisible by 3: no padding.
  • Remainder 1: standard Base64 ends with ==.
  • Remainder 2: standard Base64 ends with =.

When padding is omitted, the decoder can restore it from the encoded length. A Base64url string whose length modulo 4 is 1 is invalid, because no valid amount of padding can make it a complete Base64 quantum.

4. Encode and decode base64url

Python

import base64

raw = b"hello? world/"
encoded = base64.urlsafe_b64encode(raw).decode("ascii")
print(encoded)  # aGVsbG8_IHdvcmxkLw==

# Remove padding only if your protocol specifies unpadded base64url.
unpadded = encoded.rstrip("=")
print(unpadded)  # aGVsbG8_IHdvcmxkLw

# Restore padding before decoding.
padded = unpadded + "=" * (-len(unpadded) % 4)
decoded = base64.urlsafe_b64decode(padded)
assert decoded == raw

Node.js

const input = Buffer.from('hello? world/', 'utf8');

// Node supports the URL-safe alphabet with the base64url encoding name.
const encoded = input.toString('base64url');
console.log(encoded); // aGVsbG8_IHdvcmxkLw

const decoded = Buffer.from(encoded, 'base64url').toString('utf8');
console.log(decoded); // hello? world/

Browser JavaScript

function bytesToBase64url(bytes) {
  let binary = '';
  for (const byte of bytes) binary += String.fromCharCode(byte);
  return btoa(binary)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
}

function base64urlToBytes(value) {
  if (!/^[A-Za-z0-9_-]*$/.test(value) || value.length % 4 === 1) {
    throw new Error('Invalid unpadded base64url');
  }
  const padded = value.replace(/-/g, '+').replace(/_/g, '_'.replace('_', '/'))
    + '='.repeat((4 - value.length % 4) % 4);
  const binary = atob(padded);
  return Uint8Array.from(binary, c => c.charCodeAt(0));
}

const value = bytesToBase64url(new TextEncoder().encode('hello'));
console.log(value);

In browser code, use a byte-aware method such as TextEncoder. Calling btoa directly on arbitrary Unicode text throws for characters outside the Latin-1 range.

cURL and shell

# GNU coreutils
printf 'hello? world/' | base64 | tr '+/' '-_' | tr -d '=\n'

# Decode an unpadded value
printf 'aGVsbG8_IHdvcmxkLw' | tr -- '-_' '+/' | awk '{ printf "%s", $0; n=length($0)%4; if (n==2) printf "=="; else if (n==3) printf "=" }' | base64 --decode

Portable shell flags differ between GNU and BSD base64. For production code, prefer your language’s dedicated URL-safe Base64 API.

5. Correct handling of Unicode and binary data

Base64 encodes bytes, not characters. Convert text to UTF-8 first, then encode those bytes. When decoding, interpret the resulting bytes using the encoding your protocol specifies.

import base64

text = "café · 東京"
token = base64.urlsafe_b64encode(text.encode("utf-8")).decode("ascii").rstrip("=")
restored = base64.urlsafe_b64decode(token + "=" * (-len(token) % 4)).decode("utf-8")
assert restored == text

6. Validation and strict decoding

Strict validation prevents malformed or ambiguous values from being silently accepted. For unpadded base64url, allow only A-Z, a-z, 0-9, - and _; reject whitespace, +, / and misplaced = unless the protocol explicitly permits them.

import base64
import binascii


def decode_base64url_strict(value: str) -> bytes:
    if not value or not all(c.isalnum() or c in "-_" for c in value):
        raise ValueError("invalid base64url alphabet")
    if len(value) % 4 == 1:
        raise ValueError("invalid base64url length")
    padded = value + "=" * (-len(value) % 4)
    try:
        return base64.b64decode(padded, altchars=b"-_", validate=True)
    except (binascii.Error, ValueError) as exc:
        raise ValueError("invalid base64url value") from exc

Do not silently discard unexpected characters. Different components may otherwise validate different byte sequences, creating interoperability or security bugs.

7. Is Base64url encryption?

No. Encoding changes representation and is reversible. It does not require a secret key and does not make data confidential. Never put passwords, private keys or sensitive personal data in a Base64url string unless the data is separately encrypted and authenticated.

Signed tokens such as JWTs commonly use base64url for compact serialization, but the encoding itself supplies no integrity. Verify the token’s signature and validate claims such as issuer, audience and expiration according to that token’s protocol.

8. Where to use it

  • URL path segments and query parameters when the protocol specifies base64url.
  • Filenames and object keys where + and / are inconvenient.
  • Opaque identifiers that need a compact, ASCII representation.
  • OpenAPI schemas using contentEncoding: base64url; see the OpenAPI format registry.

Use standard Base64 when the receiving format explicitly expects it, including many data URLs and legacy APIs. Do not convert alphabets merely because a string happens to contain no + or /; follow the protocol contract.

9. Common errors and fixes

Error Cause Fix
“Invalid character” A standard Base64 decoder received - or _. Use a base64url decoder or translate -_ to +/ before decoding.
“Incorrect padding” Padding was removed but not restored, or the value is truncated. Restore = to a multiple-of-four length and reject length modulo 4 equal to 1.
Spaces appear in the decoded value A query parser treated + as a space. Use base64url or percent-encode standard Base64 correctly.
Unicode decode failure Bytes were decoded with the wrong character encoding. Encode and decode as UTF-8 when the protocol carries UTF-8 text.
Different services produce different strings One includes padding or uses standard Base64. Document alphabet and padding policy; normalize only at the protocol boundary.
Secret data is visible Base64url was mistaken for encryption. Use authenticated encryption, then encode the ciphertext if transport requires text.

10. Performance, size and reliability

Base64 expands data by roughly one third: three bytes become four characters, plus optional padding. The extra size affects URL length limits, headers, logs and storage. Encode once at the boundary, avoid repeated decode/re-encode cycles, and stream large binary files instead of placing them in URLs.

For reliable integrations, specify all of the following in the API contract: standard Base64 or base64url, padded or unpadded output, accepted whitespace, maximum length, byte encoding, and strict versus permissive decoding. Test empty input, one- and two-byte inputs, binary bytes containing zeroes, Unicode text and malformed characters.

11. Or skip the browser setup

If you need a URL-safe value for a screenshot workflow, ScreenshotNeo returns the image directly from one API request, so you do not need to install or operate a browser. See the ScreenshotNeo API docs for all options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Cookie banners, newsletter popups and chat widgets are removed before the shot. Bot checks, blank pages and failed loads are never billed, and response headers identify the page verdict and billing result. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

12. FAQ

Why does my token contain hyphens and underscores?

Those are the base64url replacements for standard Base64’s plus and slash characters.

Should I remove the equals signs?

Only when the protocol defines unpadded base64url or the decoder can infer the missing padding.

Can I decode base64url with a normal Base64 library?

Only if the library supports the URL-safe alphabet or you translate the two characters and restore padding correctly.

Is base64url smaller than Base64?

No. The encoded size is effectively the same; removing padding saves at most two characters.

Is a Base64 URL the same as a data URL?

No. A data URL is a URI scheme that may contain standard Base64. Base64url is an alphabet and padding profile.