All posts
June 3, 20265 min read

URL encoding explained: why spaces become %20 and when you need it

A URL can only safely contain a limited set of characters. Everything else, spaces, accented letters, slashes that are data rather than path separators, has to be percent-encoded: replaced with a % followed by the byte's hex value. A space becomes %20, an ampersand becomes %26. Knowing the rules stops a recurring family of bugs in query strings, redirects, and API calls.

Why encoding exists

URLs have structure. The ? starts the query string, & separates parameters, = joins keys to values, # starts the fragment, / separates path segments. If your actual data contains one of those characters, the parser cannot tell your data from the structure. Encoding the data first removes the ambiguity: an encoded %26 is unmistakably the literal character "&" and not a parameter separator. Encode and decode either direction with the URL Encoder / Decoder.

Reserved versus unreserved

The spec splits characters into groups. Unreserved characters, the letters, digits, and - . _ ~, never need encoding. Reserved characters have meaning in a URL and must be encoded when they appear as data rather than structure. Everything else, including spaces and most non-ASCII, is always encoded. Non-ASCII is first turned into UTF-8 bytes, then each byte is percent-encoded, which is why an emoji expands into several %xx pairs.

encodeURI versus encodeURIComponent

This is the distinction that trips people up in JavaScript:

  • encodeURIComponent encodes almost everything, including /, ?, &, and =. Use it for a single piece of data you are dropping into a URL, like one query parameter value.
  • encodeURI leaves the structural characters alone because it assumes you are encoding a whole URL. Use it only when you have a complete URL that just needs its spaces and unsafe characters cleaned up.

The common bug is using encodeURI on a value that contains a & or =. Those survive un-encoded and the receiving server reads your one value as several parameters. When in doubt for a single value, reach for encodeURIComponent.

Practical cases

  • Building query strings by hand: encode each value with component encoding before joining with &. Better still, let URLSearchParams do it.
  • Redirect parameters: a ?next= value that is itself a URL must be fully component-encoded, or its own query string leaks into the outer one.
  • Reading logs: a string full of %20 and %3A is just an encoded URL. Paste it into the URL Encoder / Decoder to read it.

Encoding and Base64 are often confused because both produce odd-looking strings, but they solve different problems: encoding makes data safe for a URL, Base64 makes binary safe for text. If that line is fuzzy, Base64 is not encryption clears it up, and the Base64 tool handles the other case.