Why URLs Cannot Contain All Characters
The URL specification (RFC 3986) defines which characters are allowed in a URL. These are called "unreserved characters": letters (A-Z, a-z), digits (0-9) and the four symbols: - _ . ~
Every other character is either a "reserved character" (which has special meaning in URL structure, like / : ? & =) or an "unsafe character" (like spaces and non-ASCII text) that cannot appear in a URL at all.
The problem: real-world data — search queries, names, addresses, passwords — contains spaces, ampersands, equal signs, special characters and often non-English text. All of these need to be transmitted in URLs safely.
The solution: percent encoding, which replaces each unsafe character with % followed by its two-digit hexadecimal ASCII or UTF-8 code.
How Percent Encoding Works
The encoding process is simple: 1. Take the character that needs encoding 2. Find its ASCII or UTF-8 byte value in hexadecimal 3. Prefix it with %
Common examples: Space (ASCII 32, hex 20) → %20 Ampersand & (ASCII 38, hex 26) → %26 Equals sign = (ASCII 61, hex 3D) → %3D Plus sign + (ASCII 43, hex 2B) → %2B Hash # (ASCII 35, hex 23) → %23 Forward slash / (ASCII 47, hex 2F) → %2F
Non-ASCII characters (like Hindi or Chinese text) are encoded using their UTF-8 byte sequence. The Hindi word नमस्ते would encode to %E0%A4%A8%E0%A4%AE%E0%A4%B8%E0%A5%8D%E0%A4%A4%E0%A5%87
You may also notice spaces encoded as + signs in some URLs. This is the HTML form encoding standard (application/x-www-form-urlencoded), used when forms are submitted. In standard URLs, spaces must be %20.
encodeURI vs encodeURIComponent in JavaScript
JavaScript provides two built-in encoding functions, and choosing the wrong one is a common mistake:
encodeURI(url) — encodes a complete URL. It leaves the structural characters (/ : ? & = # @) unencoded because they are part of the URL structure and should not be changed.
Use case: encoding a full URL before storing or transmitting it.
Example: encodeURI("https://example.com/search?q=hello world") → "https://example.com/search?q=hello%20world"encodeURIComponent(value) — encodes everything, including / : ? & = #. It is designed for encoding individual query parameter values, not full URLs.
Use case: encoding a query string value before appending it to a URL.
Example: encodeURIComponent("name=Neeraj&city=Meerut") → "name%3DNeeraj%26city%3DMeerut"The most common bug: developers use encodeURI on a query parameter value, which leaves & and = unencoded, breaking the URL structure. Always use encodeURIComponent for parameter values.
URL Encoding in Other Languages
Every server-side language has built-in URL encoding:
Python: urllib.parse.quote(string) encodes special characters. urllib.parse.quote_plus(string) also converts spaces to +. For full URLs, use urllib.parse.quote(url, safe='/:@?=&#')
PHP: urlencode($string) encodes everything and converts spaces to +. rawurlencode($string) uses %20 for spaces (RFC 3986 compliant). For decoding: urldecode() and rawurldecode().
Node.js: Use the built-in encodeURIComponent() (same as browser JavaScript). For decoding: decodeURIComponent().
Java: URLEncoder.encode(string, StandardCharsets.UTF_8) encodes for form data (spaces → +). For strict RFC 3986, use URI.create(string).toASCIIString().
Go: url.QueryEscape(string) for query parameters. url.PathEscape(string) for path segments.
Common URL Encoding Mistakes
Double encoding — encoding an already-encoded string. If %20 is encoded again, it becomes %2520. Always decode before re-encoding to avoid this.
Encoding the wrong parts — the scheme (https://), host (example.com) and path separators (/) should never be encoded. Only query string values and path parameters need encoding.
Missing encoding in redirect URLs — if a redirect URL contains & or = as part of a parameter value (e.g. a return URL), these must be encoded or they will be interpreted as query string delimiters.
Forgetting non-ASCII content — domain names with non-ASCII characters (internationalized domain names) need Punycode encoding, not percent encoding. For example, मंत्री.com would be encoded as xn--h2brj9b7b.com.
Using the wrong encoding for the context — URL paths use %2F for slashes and %20 for spaces. HTML attributes need HTML entity encoding (& for &). HTTP headers need MIME encoding. Never mix these up.