URL Encoding Explained: Percent-Encoding, encodeURI vs encodeURIComponent
April 2, 2026 · 5 min read
A URL can only contain a limited set of ASCII characters. Spaces, non-ASCII characters, and several punctuation marks are not allowed in raw form. URL encoding — also called percent-encoding — converts these characters into a safe format that any system can transmit without ambiguity.
How Percent-Encoding Works
Each unsafe character is replaced by a percent sign followed by the two-digit hexadecimal code of the character's UTF-8 byte value:
Space → %20 / → %2F : → %3A @ → %40 ? → %3F # → %23 & → %26 = → %3D café → caf%C3%A9
The characters A–Z, a–z, 0–9 and - _ . ~ are "unreserved" and are never encoded.
Reserved vs Unreserved Characters
RFC 3986 divides URL characters into two categories:
| Category | Characters | Meaning |
|---|---|---|
| Unreserved | A–Z a–z 0–9 - _ . ~ | Safe in any part of a URL, never encoded |
| Reserved | : / ? # [ ] @ ! $ & ' ( ) * + , ; = | Have special meaning in URL structure — encode if used as data |
JavaScript: encodeURI vs encodeURIComponent
JavaScript has two built-in encoding functions, and choosing the wrong one is a very common bug.
encodeURI()
Encodes a complete URL. It does NOT encode characters that have a structural role in a URL — : / ? # @ & = — because doing so would break the URL structure.
encodeURI("https://example.com/search?q=hello world&lang=en")
// "https://example.com/search?q=hello%20world&lang=en"
// Note: ? & = are NOT encoded — they keep their structural meaningencodeURIComponent()
Encodes a component of a URL (a query parameter value, a path segment). It encodes everything except unreserved characters — including : / ? # @ & =.
encodeURIComponent("hello world & more")
// "hello%20world%20%26%20more"
// Build a query string safely:
const q = encodeURIComponent("C++ & Java");
const url = `https://example.com/search?q=${q}`;
// "https://example.com/search?q=C%2B%2B%20%26%20Java"The rule
Use encodeURI() for a full URL. Use encodeURIComponent() for individual parameter values. When in doubt, use encodeURIComponent() — it's safer.
Python
from urllib.parse import quote, quote_plus, urlencode
# Encode a path segment (/ is safe)
quote("/path/to résumé") # "/path/to%20r%C3%A9sum%C3%A9"
# Encode a query parameter value (/ is encoded too)
quote("hello world", safe="") # "hello%20world"
# Build a query string
urlencode({"q": "hello world", "lang": "en"})
# "q=hello+world&lang=en" (note: + for spaces in query strings)Space: %20 vs +
Spaces can be encoded as either %20 or + depending on context:
| Encoding | When to use |
|---|---|
| %20 | In URL paths and most modern contexts. Always correct. |
| + | In application/x-www-form-urlencoded query strings (HTML forms). Not valid in paths. |
Try It
Use the Text Tools on io9.me to URL-encode and decode strings instantly — including both standard and form-encoded modes.