ToolSite
All posts

Base64 vs URL Encoding: What's the Difference?

Base64 encodes binary data for text transport; URL encoding makes strings safe for query strings and paths. Learn when to use each and why Base64 fails in URLs.

By ToolSite4 min readguides

Quick Comparison

Base64 and URL encoding (also called percent-encoding) solve different problems, but they are often confused because both turn data into safe text strings.

Base64URL Encoding
PurposeEncode binary into textEncode text into URL-safe text
TargetAny byte sequenceReserved characters in URLs
Mechanism3 bytes becomes 4 ASCII charsUnsafe char becomes %XX hex
Expands output~33% largerVariable (space becomes %20, 3x)
ReversibleYes (encoding, not encryption)Yes (encoding, not encryption)

When to Use Base64

Use Base64 when you need to embed binary data in a text-only context:

  • Embedding an image inside a JSON payload for an API response
  • Sending a file attachment via email (MIME)
  • Storing a cryptographic key in a .pem file
  • Embedding an inline image in CSS with a data URI like data:image/png;base64,...

Base64 is not concerned with what makes a valid URL. Its alphabet was designed for email and text storage, not for query strings.

When to Use URL Encoding

Use URL encoding when you need to pass arbitrary text through a URL:

  • Submitting a form with spaces or special characters (GET method)
  • Building a query string like ?q=hello+world&lang=en
  • Including a URL inside another URL as a parameter

URL encoding converts a small set of reserved and unsafe characters into their %-prefixed hexadecimal equivalents. For example:

  • Space becomes %20 (or + in application/x-www-form-urlencoded)
  • & becomes %26
  • # becomes %23
  • / becomes %2F

The Problem with Base64 in URLs

Standard Base64 uses three characters that have special meaning in URLs:

+  ->  interpreted as a space in query strings
/  ->  interpreted as a path separator
=  ->  interpreted as a key-value delimiter in query strings

Consider a Base64-encoded string inside a query string:

Plain:   https://example.com/verify?token=aGVsbG8=
Result:  The = may be misinterpreted by some parsers.

You can technically percent-encode the Base64 string to make it URL-safe, but that is wasteful. Every +, /, and = needs to be individually encoded into %2B, %2F, and %3D. A string that was already 33 percent larger than the original binary now gets even longer.

The real solution is Base64url, a variant that replaces + with -, / with _, and omits padding entirely. This is what JWTs and modern token formats use.

base64url: The URL-Safe Variant

Base64url is defined in RFC 4648 Section 5. It makes two changes to standard Base64:

  1. Replace + with - (minus)
  2. Replace / with _ (underscore)
  3. Remove trailing = padding

Since - and _ are unreserved characters in URLs, a Base64url string can appear anywhere in a URL without additional encoding. This is why JWT segments between the dots never contain +, /, or =.

Most Base64 libraries support Base64url via a flag or a separate function:

import base64
data = b'{"user":"alice"}'
std = base64.b64encode(data)       # b'eyJ1c2VyIjoiYWxpY2UifQ=='
url = base64.urlsafe_b64encode(data)  # b'eyJ1c2VyIjoiYWxpY2UifQ'
// Standard Base64
btoa('{"user":"alice"}')  // "eyJ1c2VyIjoiYWxpY2UifQ=="

// Base64url (manual)
btoa('{"user":"alice"}')
  .replace(/\+/g, '-')
  .replace(/\//g, '_')
  .replace(/=+$/, '')

Double Encoding: A Common Mistake

A pitfall worth knowing: if you Base64-encode something, then URL-encode the result, you are doing double work. Either use Base64url directly and skip URL encoding, or URL-encode the raw data and skip Base64. Mixing both wastes bytes and makes debugging harder.

The exception is when you are stuck with a system that only produces standard Base64 and you have no control over it. In that case, URL-encoding the Base64 output is a necessary workaround, but it should not be your first choice.

Worked Example

Take a simple JSON payload:

{"user":"alice","role":"admin"}

Base64 (standard):

eyJ1c2VyIjoiYWxpY2UiLCJyb2xlIjoiYWRtaW4ifQ==

If you paste this into a URL query string as-is, the == may cause issues depending on the parser.

Base64url (URL-safe):

eyJ1c2VyIjoiYWxpY2UiLCJyb2xlIjoiYWRtaW4ifQ

No +, /, or =. Safe for any URL context.

URL encoding of the same JSON (if you were sending it as a query parameter):

%7B%22user%22%3A%22alice%22%2C%22role%22%3A%22admin%22%7D

Lines are dramatically longer because every non-alphanumeric character becomes %XX. For binary data, this blows up far more than Base64 does. URL encoding is the right tool for short text values in query strings. It is the wrong tool for embedding binary blobs.

Try it yourself: open the Base64 Encoder/Decoder and paste {"user":"alice","role":"admin"}. Compare the standard Base64 output with the Base64url option. Then open the URL Encoder/Decoder and encode the same JSON to see how percent-encoding handles every {, ", and :. Finally, paste a Base64url string directly into a URL bar as a hash fragment and confirm the browser does not mangle it.

Related Reading