Skip to main content

URL Encoding vs Base64: How to Tell Them Apart and When to Use Each

A developer's guide to URL encoding and Base64 encoding — what each one does, how to recognize them on sight, real input/output examples, and a quick debugging checklist for HTTP requests.

Published By Lei Li
#encoding #developer #web #debugging

URL Encoding vs Base64: How to Tell Them Apart and When to Use Each

The two encodings show up constantly in HTTP — in query strings, in Authorization headers, in JSON payloads, in JWTs. They look superficially similar (both turn bytes into printable characters) but they are built for different jobs, and mixing them up causes subtle bugs that are annoying to track down.

This guide cuts straight to recognition and usage: what each encoding looks like in the wild, when to reach for one over the other, and how to diagnose the common mistake of applying the wrong one.

What URL Encoding Actually Does

URL encoding — also called percent encoding (RFC 3986) — converts characters that would break a URL into %HH sequences, where HH is the byte's hexadecimal value.

The unreserved characters that never need encoding are: A–Z, a–z, 0–9, -, ., _, ~. Everything else either gets percent-encoded or, in a form body (application/x-www-form-urlencoded), a space becomes +.

Real input → real output:

Input:  hello world & name=Léa
Output: hello+world+%26+name%3DL%C3%A9a    (form-encoded)
        hello%20world%20%26%20name%3DL%C3%A9a  (RFC 3986 query)

The é character in "Léa" is encoded as %C3%A9 because UTF-8 encodes é as two bytes: 0xC3 and 0xA9.

URL encoding is not a compression scheme. The output is always at least as long as the input, and characters outside the unreserved set expand — a single & becomes three characters (%26). The Mozilla MDN documentation notes that encodeURIComponent encodes all characters except A–Z a–z 0–9 - _ . ! ~ * ' ( ), so if you have ever wondered why a ! survives unencoded, that is why.

Use Toolora's URL Encoder / Decoder to try any string interactively — it shows both the RFC 3986 component form and the form-encoded form side by side, which is useful when debugging a redirect URL that includes a nested query string.

What Base64 Does

Base64 takes raw bytes — any bytes, including null bytes and binary data — and maps every 3 bytes into 4 printable ASCII characters drawn from A–Z, a–z, 0–9, +, /, with = padding to align to a 4-character boundary.

Real input → real output:

Input (bytes as hex): 48 65 6C 6C 6F 20 F0 9F 8C 8E
Input (text):         Hello 🌎
Output (Base64):      SGVsbG8g8J+Mjg==

The Base64 string SGVsbG8g8J+Mjg== contains + and = — characters that URL encoding would escape. That is why JWTs and attachment-style APIs use Base64url instead, which swaps +- and /_ and drops the = padding:

Output (Base64url):   SGVsbG8g8J-Mjg

The RFC 4648 standard specifies that Base64 inflates the original data by exactly 4/3 — a 33% size increase. A file that is 300 bytes becomes 400 characters of Base64 text. That overhead is predictable and calculable without running the encoding.

Toolora's Base64 Encoder / Decoder handles plain text, files, and raw hex input, and also shows the output character count alongside the input byte count so the 33% growth is visible immediately.

Recognizing Each on Sight

I have spent time reading raw HTTP logs, and after a while the two encodings become easy to tell apart without decoding:

| Signal | URL encoding | Base64 | |---|---|---| | Contains % | Almost always | Never (Base64url might have - _) | | Contains + | Yes (form bodies) | Yes (standard Base64 only) | | Contains = | No (reserved char, encoded as %3D) | Yes, at the end for padding | | Length relative to input | Variable expansion per char | Always ~133% of byte count | | Looks like words | Often — hello%20world is readable | Rarely — SGVsbG8= is opaque | | Valid alone in a URL | Yes | Only if Base64url variant is used |

The fastest rule: if a string has %20, %2F, %3D, or similar two-hex-digit sequences after a %, it is URL-encoded. If it is a solid block of letters, digits, +, /, and trailing =, it is Base64.

When to Use Each

Use URL encoding when the data is text and it must live inside a URL component: a query parameter value, a path segment, a redirect target, a fragment. The encoding tells the HTTP client and server which characters are structural (the ?, &, = delimiters) and which are data.

A common mistake: a developer takes a JWT or a Base64 payload and URL-encodes it instead of using Base64url. The + and / characters in standard Base64 become %2B and %2F, the string decodes back correctly on a careful server, but breaks on any server that partially decodes first and then re-encodes, or that treats %2F as a path separator.

Use Base64 when the data is binary or byte-oriented and must be transported through a text channel. Classic cases:

  • Images embedded in CSS as data: URIs
  • File attachments in JSON APIs (when multipart is not available)
  • Cryptographic signatures and nonces in Authorization headers
  • JWT payloads (using Base64url specifically)
  • Binary blobs inside XML or HTML attributes

Use Base64url specifically when the encoded string must also be URL-safe — JWT header/payload/signature segments, OAuth 2.0 PKCE code verifiers, and any Base64 that will appear in a query parameter. Toolora's Base64url Encoder / Decoder for JWT-safe strings is purpose-built for this: it generates padded or unpadded output and validates the alphabet so you can spot a + or / that leaked from standard Base64.

A Quick Debugging Checklist

When an encoded value is coming through garbled or mismatched, I run through these steps:

  1. Look at the raw value before any automatic decoding. Browser DevTools → Network → Headers shows the raw bytes. curl -v shows them too. If you see %, you have percent encoding. If you see a solid alphanumeric block with possible + and trailing =, you have Base64.
  1. Check where in the URL it lives. A query parameter value should be URL-encoded. An Authorization: Bearer header token should be Base64url (no padding, no +, no /). A Content-Type: application/json body field carrying binary data should be Base64 or Base64url.
  1. Try decoding one layer at a time. A double-encoded value — Base64 of a URL-encoded string — is a common accident. Decode the outer layer first and check whether the inner result makes sense.
  1. Check the size. If an encoded string is 33% longer than the original byte count, you are looking at Base64. If it is the same length as the original but with %XX sequences substituting some characters, you are looking at URL encoding.
  1. Validate the alphabet. A valid standard Base64 string contains only [A-Za-z0-9+/=]. A valid Base64url string contains only [A-Za-z0-9\-_] (no +, /, or =). A valid percent-encoded string has % followed by exactly two hex digits each time. Any deviation means the encoding was corrupted in transit.

Keeping a fast encoder/decoder open while debugging saves constant round-trips to documentation. The URL Encoder / Decoder and Base64 Encoder / Decoder on Toolora accept raw input and show the output immediately, which makes step 3 above take about five seconds.

The One-Sentence Summary

URL encoding preserves URL structure by escaping characters that would otherwise mean something to a parser; Base64 encoding makes arbitrary bytes safe to carry through text-only systems, at the cost of a predictable 33% size increase. Pick based on what the data is (text vs. bytes) and where it must go (URL vs. body vs. header).


Made by Toolora · Updated 2026-07-01