URL Encoding Explained: Percent Encoding in Web Development
URLs look simple on the surface, but they follow a strict specification that limits which characters are allowed and where. When you need to include spaces, special characters, or non-ASCII text in a URL, you must encode them using a mechanism called percent encoding — commonly known as URL encoding.
This guide explains how URL encoding works, which characters need encoding, and how to do it correctly in code.
Why URLs Need Encoding
URLs were defined in RFC 3986 and only permit a specific set of ASCII characters. Some characters (like /, ?, &, =) have reserved meanings in URL structure. Others (like spaces, quotes, or non-ASCII characters) are simply not allowed in raw form.
Consider this search URL:
https://example.com/search?q=hello world&lang=en
The space in "hello world" would break the URL. Percent-encoded, it becomes:
https://example.com/search?q=hello%20world&lang=en
How Percent Encoding Works
Each encoded character is represented as % followed by two uppercase hexadecimal digits — the UTF-8 byte value of the character:
| Character | Encoded | UTF-8 byte |
|---|---|---|
| space | %20 | 0x20 |
| ! | %21 | 0x21 |
| # | %23 | 0x23 |
| & | %26 | 0x26 |
| + | %2B | 0x2B |
| / | %2F | 0x2F |
| = | %3D | 0x3D |
| ? | %3F | 0x3F |
| @ | %40 | 0x40 |
| é (non-ASCII) | %C3%A9 | 0xC3 0xA9 (UTF-8) |
Safe Characters (Never Need Encoding)
These characters are always safe in URLs and should never be encoded:
A-Z a-z 0-9 - _ . ~
Everything else should be percent-encoded when used in a URL component where it would otherwise be ambiguous.
Reserved vs Unreserved Characters
RFC 3986 distinguishes between:
- Unreserved characters — always safe: letters, digits,
-,_,.,~ - Reserved characters — safe only in specific URL positions where they carry their reserved meaning:
: / ? # [ ] @ ! $ & ' ( ) * + , ; = - Everything else — must be percent-encoded
The key insight: a / in a path segment is a path separator and should NOT be encoded. A / that is a literal character (e.g., in a file name) MUST be encoded as %2F.
URL Encoding in JavaScript
JavaScript provides three built-in functions, each with different scope:
encodeURIComponent — use for parameter values
encodeURIComponent("hello world & friends")
// → "hello%20world%20%26%20friends"
// Building a query string safely:
const q = encodeURIComponent(userInput);
const url = `https://api.example.com/search?q=${q}`;
encodeURI — use for full URLs
encodeURI("https://example.com/search?q=hello world")
// → "https://example.com/search?q=hello%20world"
// Note: does NOT encode : / ? & = # (they retain URL meaning)
URLSearchParams — the modern approach
const params = new URLSearchParams({
q: 'hello world & more',
page: 1,
lang: 'en'
});
const url = `https://api.example.com/search?${params}`;
// → "https://api.example.com/search?q=hello+world+%26+more&page=1&lang=en"
Note: URLSearchParams uses + for spaces (application/x-www-form-urlencoded format) rather than %20. Both are valid in query strings, but %20 is more universally accepted.
URL Encoding in Python
from urllib.parse import quote, quote_plus, urlencode
# Encode a single component (path segment or value)
quote("hello world & friends")
# → "hello%20world%20%26%20friends"
# Build query string from dict
urlencode({"q": "hello world", "lang": "en"})
# → "q=hello+world&lang=en"
Common Mistakes
Double-encoding
// Wrong — encoding an already-encoded URL
encodeURIComponent("hello%20world")
// → "hello%2520world" (% itself gets encoded to %25)
Always encode raw values, not pre-encoded strings.
Using + for spaces in path segments
The +-as-space convention only applies to the query string (and form data). In path segments, spaces must be encoded as %20. Using + in a path will be treated as a literal plus sign.
Frequently Asked Questions
What is the difference between %20 and + for spaces?
Both represent spaces, but in different contexts. %20 is universal and works everywhere in a URL. + means space only in the query string (application/x-www-form-urlencoded format). In path segments, + is a literal plus sign. When in doubt, use %20.
What is the difference between encodeURI and encodeURIComponent?
encodeURI encodes a full URL and preserves characters that have URL-level meaning (/, ?, #, &, =). encodeURIComponent encodes a URL component (path segment or query value) and also encodes those structural characters. Use encodeURIComponent for individual parameter values.
Do I need to encode forward slashes in a URL path?
Only if the slash is a literal character in a path segment — for example, a date like "2026/05/07" used as a single parameter value. If you want the slash to act as a path separator, leave it unencoded. If you're putting a value containing slashes into a query parameter, use encodeURIComponent, which will encode them as %2F.