URL Encoding Explained

Percent encoding, encodeURI vs encodeURIComponent, and when to use each.

URLs can only contain a specific set of ASCII characters. Everything else — spaces, accented letters, symbols like & or =, non-Latin characters, emoji — must be converted into a safe format before being placed in a URL. This conversion is called URL encoding or percent encoding. Getting it wrong breaks links, causes 400 API errors, and creates security vulnerabilities.

How Percent Encoding Works

A character that cannot appear in a URL is replaced by a percent sign followed by two hexadecimal digits representing the character's UTF-8 byte value:

Character Encoded form Notes
Space%20Also + in form data
&%26Separates query params if unencoded
=%3DSeparates key=value if unencoded
+%2BUnencoded + means space in form data
#%23Fragment separator if unencoded
/%2FPath separator if unencoded
£%C2%A3Multi-byte UTF-8 character
😀%F0%9F%98%804-byte UTF-8 emoji

Safe Characters — No Encoding Needed

The RFC 3986 specification defines unreserved characters that are always safe in URLs without encoding:

A–Z  a–z  0–9  -  _  .  ~

Everything else must be encoded when it appears as data (not as part of the URL's structure).

encodeURI vs encodeURIComponent — The Critical Distinction

JavaScript provides two built-in URL encoding functions. Confusing them is one of the most common URL-related bugs:

// encodeURI — encodes a complete URL
// Preserves: : / ? # [ ] @ ! $ & ' ( ) * + , ; =
encodeURI('https://example.com/search?q=hello world&lang=en')
// → 'https://example.com/search?q=hello%20world&lang=en'

// encodeURIComponent — encodes a URL component (a value)
// Encodes ALL special characters including : / ? # & =
encodeURIComponent('hello world&lang=en')
// → 'hello%20world%26lang%3Den'

// ✅ Correct: build URL safely
const query = 'price < £100';
const url = `https://example.com/search?q=${encodeURIComponent(query)}`;
// → 'https://example.com/search?q=price%20%3C%20%C2%A3100'

Rule: Use encodeURIComponent() whenever you are inserting a dynamic value into a URL (query string parameter, path segment, fragment). Use encodeURI() only when encoding an already-assembled URL that just needs unsafe characters cleaned up.

URLSearchParams — The Modern Alternative

In modern JavaScript, URLSearchParams handles query string encoding automatically and is often cleaner than manual encoding:

const params = new URLSearchParams({
  q: 'price < £100',
  category: 'finance & tax',
  page: '1'
});
const url = `https://example.com/search?${params.toString()}`;
// → 'https://example.com/search?q=price+%3C+%C2%A3100&category=finance+%26+tax&page=1'

Note that URLSearchParams encodes spaces as + (form-encoding style) rather than %20 — both are valid for query strings.

Common URL Encoding Mistakes

  • Using encodeURI instead of encodeURIComponent on values. If a query string value contains & or =, encodeURI will not encode them, breaking the URL structure.
  • Double encoding. Encoding an already-encoded URL encodes the % signs: %20 becomes %2520. Always decode before encoding again.
  • Not encoding path segments. If a file name or slug contains spaces or special characters, the path must be encoded too — not just the query string.
  • Forgetting to decode in server-side code. URL parameters arrive at the server encoded. Most frameworks decode them automatically, but manual string handling in middleware may miss this.
  • Manually building URLs with string concatenation. Always use URL, URLSearchParams, or a URL-building library instead of string concatenation — they handle encoding for you.

Decoding URLs

decodeURI('https://example.com/search?q=hello%20world')
// → 'https://example.com/search?q=hello world'

decodeURIComponent('hello%20world%26lang%3Den')
// → 'hello world&lang=en'
Advertisement

Frequently Asked Questions

What is URL encoding?

Conversion of characters not allowed in URLs into a safe format: a percent sign followed by two hex digits. For example, space → %20, & → %26, £ → %C2%A3.

What is the difference between encodeURI and encodeURIComponent?

encodeURI() encodes a full URL — preserving structural characters like /, ?, #, &, =. encodeURIComponent() encodes a URL component value — encoding ALL special characters. Use encodeURIComponent() for dynamic values inserted into URLs.

Which characters need to be URL encoded?

Only A-Z, a-z, 0-9, and the four symbols - _ . ~ are always safe. Everything else (spaces, &, =, #, /, non-ASCII characters) must be encoded when used as data in a URL.

How are spaces encoded in URLs?

%20 in standard URL encoding. + in HTML form submissions (application/x-www-form-urlencoded). encodeURIComponent() produces %20; URLSearchParams produces +. Both are valid in query strings.

Why does my API return a 400 error with special characters?

Almost always because query string values contain unencoded special characters (&, =, +, ?) that break URL parsing. Always pass dynamic values through encodeURIComponent() before inserting into a URL.