I still remember the first time URL encoding bit me. I was building a search feature and passed a query like q=hello world directly into a fetch call. It worked on my machine, failed in production, and took an embarrassingly long time to figure out that the space was the culprit.

That is the thing about URL encoding: it is invisible until it breaks. This guide explains what percent-encoding actually does, when you need it, and the common mistakes that trip up even experienced developers.

What URL Encoding Actually Does

URLs can only safely contain a limited set of characters: letters, digits, and a handful of symbols like -, ., _, ~. Everything else has to be converted into a percent sign followed by two hexadecimal digits.

Space → %20
!     → %21
@     → %40
#     → %23
&     → %26
=     → %3D

So hello world becomes hello%20world, and coffee & donuts becomes coffee%20%26%20donuts. The URL itself stays valid ASCII, and the server knows how to decode it back on the other end.

Why This Matters

A URL is not just a string. It has structure: scheme, host, path, query parameters, fragment. If a special character appears where the parser expects structure, the whole thing falls apart.

For example, & separates query parameters. If your data contains an &, the server will split it incorrectly unless you encode it first.

?query=coffee & donuts
// Server sees: query=coffee, and an unknown parameter named ' donuts'

?query=coffee%20%26%20donuts
// Server correctly sees: query=coffee & donuts

Reserved Characters and When to Encode Them

URLs reserve certain characters for special meaning:

: / ? # [ ] @ ! $ & ' ( ) * + , ; =

If you are using one of these as literal data, encode it. If it is part of the URL structure, leave it alone. The tricky part is knowing which is which, which is why JavaScript gives us two different functions.

encodeURI vs encodeURIComponent

This is where a lot of developers get confused. JavaScript has two encoding functions and they do different jobs.

encodeURI

Use this for an entire URL. It encodes characters that would break the URL but leaves structural characters alone.

encodeURI("https://example.com/path name")
// "https://example.com/path%20name"

encodeURI("https://example.com/path?name=Frank")
// "https://example.com/path?name=Frank" — leaves ? and = alone

encodeURIComponent

Use this for individual query parameter values. It encodes almost everything except letters, digits, and a few safe symbols.

encodeURIComponent("hello world")
// "hello%20world"

encodeURIComponent("https://example.com")
// "https%3A%2F%2Fexample.com"

The rule I follow: encodeURIComponent for values, encodeURI for full URLs. Never use encodeURI on a parameter value, because it will leave & and = unencoded and break your query string.

Encoding Non-ASCII Characters

Characters outside the ASCII range, like or é, have to go through two steps: first convert to UTF-8 bytes, then percent-encode each byte.

中 → %E4%B8%AD
é → %C3%A9

Modern libraries handle this automatically, but if you are manually constructing URLs in an older system, this is a common source of garbled text.

Real-World Scenarios

Building Query Strings by Hand

I avoid this when possible, but sometimes you have to:

const baseUrl = 'https://api.example.com/search';
const params = {
  query: 'tech & innovation',
  category: 'startups'
};

const queryString = Object.entries(params)
  .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
  .join('&');

const url = `${baseUrl}?${queryString}`;
// https://api.example.com/search?query=tech%20%26%20innovation&category=startups

Encode both keys and values. It feels redundant until someone passes a = in a key name.

Form Submissions

Browsers encode form data automatically before sending it. You usually do not need to do anything. But if you are constructing the same request in JavaScript for an API call, you are responsible for encoding it yourself.

Double Encoding

The most frustrating bug is encoding something that is already encoded. You end up with %2520 instead of %20, because the % itself got encoded. If your decoded value looks wrong, check whether you encoded it twice.

URL Encoding Best Practices

  • Always encode user input before putting it in a URL
  • Encode keys and values separately, not the whole URL at once
  • Use encodeURIComponent for parameter values
  • Be careful with plus signs: some systems treat + as a space in query strings, but %20 is safer

Questions I Get Asked

Should I encode the entire URL?

Usually no. Encode the components individually so you do not destroy the URL structure. Use encodeURI only when you genuinely have a full URL with unsafe characters in the path.

Why does my API receive + instead of a space?

In query strings, + is often interpreted as a space by servers. If you encode spaces as %20, you avoid this ambiguity.

Is URL encoding the same as HTML encoding?

No. URL encoding is for URLs. HTML encoding, like &, is for displaying special characters in web pages. They solve different problems.

Conclusion

URL encoding is one of those topics that seems trivial until a single unencoded & costs you an hour of debugging. The rule is simple: if the data came from a user or an external source, encode it before it touches a URL.

For quick encoding and decoding tasks, use the FastUnix URL Encoder/Decoder. If you are working with JSON payloads in API requests, the JSON Formatter can help you inspect the data before you build the query string.