Skip to main content

Base64 vs URL Encoding: When to Use Each and Common Mistakes

A practical guide to choosing Base64 or URL encoding for API parameters, redirects, data URLs, files, and tokens, with real input/output examples and a reproducible size benchmark.

Published By Lei Li
#encoding #developer #web

Base64 vs URL Encoding: When to Use Each and Common Mistakes

Base64 and URL encoding are often mentioned together because both turn unsafe input into safer text. They solve different problems. Base64 is for representing bytes as text. URL encoding, also called percent encoding, is for placing characters inside a URL without changing the URL's structure.

If you only remember one rule, make it this: use Base64 when the payload is binary or byte-oriented, and use URL encoding when the payload is a URL component. For hands-on checks, keep Toolora's Base64 Encoder/Decoder and URL Encoder / Decoder open while testing real values.

The Decision Rule

Use Base64 when the original data is not naturally URL text: a file, image, signature, cryptographic nonce, compressed blob, binary fixture, or arbitrary bytes from an API. Base64 takes 3 bytes at a time and emits 4 printable characters. That mapping is defined in RFC 4648, section 4. It is predictable, widely supported, and reversible.

Use URL encoding when the original data is already text but must sit inside a URL path segment, query parameter, fragment, or form body. RFC 3986 defines the unreserved URL characters as letters, digits, -, ., _, and ~. Other bytes can be represented as %HH, where HH is the hexadecimal byte value. A space becomes %20 in normal percent encoding, and often + in application/x-www-form-urlencoded form bodies.

The practical difference is intent. Base64 says, "Here are bytes, please carry them through text-only systems." URL encoding says, "Here is a URL part, please do not let &, =, ?, #, spaces, emoji, or non-ASCII text break the address."

There is also Base64url, the URL-safe Base64 variant. It swaps + for -, / for _, and often omits = padding. JWT segments use this shape. Base64url is still Base64. It is not the same as percent encoding.

A Real Input and the Actual Outputs

Here is one concrete input string:

email=lei+test@example.com&redirect=/pricing?plan=pro&note=coffee & tea

Standard Base64 output:

ZW1haWw9bGVpK3Rlc3RAZXhhbXBsZS5jb20mcmVkaXJlY3Q9L3ByaWNpbmc/cGxhbj1wcm8mbm90ZT1jb2ZmZWUgJiB0ZWE=

Base64url output:

ZW1haWw9bGVpK3Rlc3RAZXhhbXBsZS5jb20mcmVkaXJlY3Q9L3ByaWNpbmc_cGxhbj1wcm8mbm90ZT1jb2ZmZWUgJiB0ZWE

URL component encoded output:

email%3Dlei%2Btest%40example.com%26redirect%3D%2Fpricing%3Fplan%3Dpro%26note%3Dcoffee%20%26%20tea

Those outputs are not interchangeable. If you want to send the whole string as one query parameter, the URL-encoded version is right:

https://example.com/search?payload=email%3Dlei%2Btest%40example.com%26redirect%3D%2Fpricing%3Fplan%3Dpro%26note%3Dcoffee%20%26%20tea

The raw version is broken as one parameter because &redirect= and &note= become separate parameters. Standard Base64 is also awkward in URLs because +, /, and = may need special handling depending on where the value goes. Base64url is better for compact tokens in URLs, but you still need the receiving system to expect Base64url and decode it that way.

I tested this exact string in Node before writing the example because the + sign is where people get surprised. In an email address, lei+test@example.com means a literal plus. In form-style query parsing, + can be read as a space unless it is encoded as %2B. That single character is enough to corrupt a login lookup, webhook signature base string, or OAuth callback.

Size Benchmark: Base64 Is Predictable, Percent Encoding Depends on the Bytes

I ran a small local benchmark with a deterministic 1,024-byte payload: byte[i] = (i * 31 + 17) & 255. The same bytes were encoded two ways: standard Base64, and byte-level percent encoding where only RFC 3986 unreserved bytes stayed literal.

| Encoding | Output length | Overhead vs 1,024 raw bytes | Source rule | |---|---:|---:|---| | Base64 | 1,368 characters | +33.6% | RFC 4648 3-byte to 4-character groups | | Percent encoding | 2,544 characters | +148.4% | RFC 3986 unreserved characters plus %HH escapes |

The numeric claim here is the benchmark result, and it is reproducible from the byte pattern above. The standards explain why it happens: Base64 expands in fixed 4-character groups, while percent encoding uses 3 characters for every byte outside the unreserved set. On ordinary English query text, URL encoding can be much shorter than Base64 because most letters remain unchanged. On arbitrary binary, percent encoding can get large quickly.

That is why "which one is smaller?" is the wrong first question. Ask what the receiver expects. A JSON API field named avatarBase64 probably expects Base64. A redirect_uri query parameter expects URL component encoding. A JWT expects Base64url for each segment. A browser address bar expects a valid URL, not a Base64 blob unless the app has defined a parameter that carries one.

Common Mistakes That Cause Real Bugs

Encoding the whole URL instead of one component. If you run component encoding across https://example.com/a?x=1&y=2, the :, /, ?, =, and & characters all become escaped. That is correct only if the full URL is being placed inside another query parameter, such as redirect_uri=.... If you are building the final clickable URL, encode the parameter values, not the separators.

Using Base64 to hide secrets. Base64 is not encryption. YWRtaW46czNjcmV0 decodes to admin:s3cret without a password or private key. It is fine for Basic Auth formatting and config transport. It is not fine as a secrecy layer.

Forgetting Base64url for URL tokens. Standard Base64 may emit +, /, and =. Those characters are legal in some URL contexts but easy to mishandle in query strings, route params, logs, and copy-pasted links. For JWT-style URL tokens, use Base64url and make the decoder match.

Double-encoding percent signs. %20 is a space. %2520 is the percent sign encoded as %25, followed by 20. If a URL contains %252F where you expected %2F, it was probably encoded twice. Decode once and inspect before applying another encode pass.

Mixing form encoding with URL component encoding. In classic form bodies, spaces are often represented as +. In encodeURIComponent, a space becomes %20 and a literal plus becomes %2B. That distinction matters for emails, search queries, campaign names, and any value where + is data.

My working checklist is short. If the value is bytes, encode with Base64 or Base64url. If the value is one URL part, percent-encode that component. If the value is an entire URL being placed inside another URL, component-encode the entire inner URL. If the value is secret, encrypt or sign first, then encode for transport.


Made by Toolora · Updated 2026-06-06