Have you ever pasted a link containing spaces or special characters and watched it break? Or noticed a URL full of strange %20 and %3D symbols? That weirdness has a name: URL encoding. And once you understand it, a lot of mysterious web behavior suddenly makes sense.
Why URLs Need Encoding
URLs were designed in the early days of the internet when character sets were limited. The original specification (RFC 3986) only allows a small set of ASCII characters in URLs. Letters, digits, hyphens, periods, underscores, and tildes are fine. Everything else needs to be encoded.
Think about it: if a URL contains a & character, how does the browser know whether it's part of the path or a query parameter separator? Encoding removes that ambiguity.
How Percent Encoding Works
The mechanism is straightforward. Each byte of the character is represented as %XX, where XX is the hexadecimal value of that byte.
Space → %20
! → %21
# → %23
@ → %40
For non-ASCII characters like Chinese, Korean, or emoji, the character is first encoded as UTF-8 bytes, then each byte is percent-encoded individually. The Korean character "한" becomes %ED%95%9C because its UTF-8 representation is three bytes: ED, 95, 9C.
Reserved vs. Unreserved Characters
Not every character needs encoding. The spec splits them into two groups:
| Category | Characters | Needs Encoding? |
|---|---|---|
| Unreserved | A-Z a-z 0-9 - _ . ~ | No |
| Reserved (delimiters) | : / ? # [ ] @ ! $ & ' ( ) * + , ; = | Depends on context |
| Everything else | Spaces, non-ASCII, etc. | Always |
Reserved characters only need encoding when they appear outside their designated role. A / in the path is fine because it's serving as a path separator. But a / inside a query parameter value must be encoded as %2F.
encodeURI vs. encodeURIComponent in JavaScript
This is where most developers get confused. JavaScript gives you two functions, and picking the wrong one is a classic bug source.
// encodeURI - encodes a full URL, preserves structural characters
encodeURI("https://example.com/path?q=hello world")
// "https://example.com/path?q=hello%20world"
// encodeURIComponent - encodes a single value, encodes everything
encodeURIComponent("hello world&foo=bar")
// "hello%20world%26foo%3Dbar"
Rule of thumb: Use encodeURIComponent for parameter values. Use encodeURI only when encoding an entire URL that already has proper structure.
The Double Encoding Trap
This is the single most common mistake. Someone encodes a value, then passes it through another function that encodes it again. The % character in %20 gets re-encoded to %2520. Now your space shows up as a literal "%20" instead of an actual space.
If your URLs look weird with extra percent signs, double encoding is almost certainly the culprit. The fix is simple: encode once, at the point where you build the URL. Never encode something that's already encoded.
Spaces: %20 or +?
You'll see spaces represented two ways: %20 and +. The + convention comes from HTML form submissions (application/x-www-form-urlencoded). In the URL path, always use %20. In query strings, both work, but %20 is universally safer.
Practical Uses Beyond the Basics
- API requests - Query parameters with user input must be encoded to prevent injection and parsing errors.
- File downloads - Filenames with spaces or special characters in Content-Disposition headers need encoding.
- Email mailto links - Subject lines and body text in mailto: URLs require percent encoding.
- Internationalized domain names - Non-ASCII domain names use Punycode, but the path and query still use percent encoding.
Quick Reference
- Encode parameter values with
encodeURIComponent - Never encode an already-encoded string
- Use
%20for spaces in paths,+is only for form data - Non-ASCII characters are UTF-8 encoded first, then percent-encoded
- When in doubt, encode it
URL Structure in Detail
To truly understand URL encoding, you need to understand the anatomy of a URL as defined in RFC 3986.
https://user:[email protected]:8080/path/to/page?key=value&q=test#section
scheme: https
authority: user:[email protected]:8080
path: /path/to/page
query: key=value&q=test
fragment: section
Scheme: The protocol identifier. Common ones are http, https, ftp, and mailto. It is separated from the rest by a colon and double slashes.
Authority: Composed of optional user info, the hostname, and an optional port number. Including credentials in the URL is discouraged for security reasons.
Path: The hierarchical location of the resource on the server, separated by /. Special characters within individual path segments need encoding.
Query: Key-value pairs after the ?, separated by &. This is where encoding is most frequently needed.
Fragment: The part after #, pointing to a specific section within the page. It is processed only by the browser and never sent to the server.
Each component has subtly different encoding rules. For example, / is a valid separator in the path and should not be encoded there, but if it appears inside a query value, it must be encoded as %2F. This context-dependence is what makes URL encoding tricky.
Non-ASCII and Unicode in URLs
Handling non-ASCII characters like Chinese, Korean, Japanese, Arabic, or emoji is a common challenge. These characters are not part of the original URL specification and must always be encoded.
The process works in two steps: first, the character is converted to its UTF-8 byte sequence, then each byte is percent-encoded individually. A single emoji can produce 12 or more characters in its encoded form.
"cafe" → cafe (ASCII, no encoding needed)
"cafe" → caf%C3%A9 (the accented e is 2 UTF-8 bytes)
"한" → %ED%95%9C (Korean character, 3 UTF-8 bytes)
Modern browsers display decoded Unicode in the address bar for readability, but the actual HTTP request always contains the encoded form. This is a presentation convenience, not how the data travels over the network.
Internationalized Domain Names (IDN): Domain names containing non-ASCII characters (like "example.de" with umlauts) use Punycode encoding rather than percent encoding. The path and query, however, use standard percent encoding.
URL Encoding in Other Languages
Beyond JavaScript, every major programming language offers URL encoding functions. The names and behaviors differ, so knowing the specifics of your language matters.
# Python
from urllib.parse import quote, quote_plus
quote("hello world") → hello%20world
quote_plus("hello world") → hello+world
// Java
URLEncoder.encode("hello world", "UTF-8") → hello+world
// PHP
urlencode("hello world") → hello+world
rawurlencode("hello world") → hello%20world
A critical distinction: Python's quote() vs. quote_plus(), PHP's urlencode() vs. rawurlencode(), and Java's URLEncoder.encode() all handle spaces differently. The + vs. %20 difference can cause subtle bugs in API integrations between systems written in different languages.
The Space Encoding Problem: %20 vs. +
Two competing conventions for encoding spaces create one of the most common sources of confusion.
%20 is the standard percent encoding defined in RFC 3986. It works everywhere in a URL: path, query, and fragment.
+ is specific to the application/x-www-form-urlencoded format used by HTML form submissions. When a browser submits a form, it replaces spaces with + signs.
The practical rule: always use %20 in URL paths. In query strings, both work, but %20 is universally safer. Only worry about + when you are specifically dealing with HTML form data.
Debugging URL Encoding Issues
When you hit a URL encoding bug, a systematic approach will find the root cause quickly.
Step 1: Check the actual request URL. Open your browser's developer tools, go to the Network tab, and look at the raw URL being sent. The address bar display may differ from the actual request.
Step 2: Look for double encoding. If you see %25 in the URL, double encoding is the likely culprit. %2520 is a space that has been encoded twice.
Step 3: Trace encoding/decoding points. Identify every point in your code where encoding or decoding happens. Frameworks and libraries often encode or decode automatically. If you add your own encoding on top, you get double encoding.
Step 4: Verify character set consistency. Confirm that both client and server use the same character encoding (usually UTF-8). If non-ASCII characters appear garbled, a charset mismatch between UTF-8 and another encoding (like ISO-8859-1 or EUC-KR) is the likely cause.
Security Implications of URL Encoding
URL encoding is closely tied to web security. Incorrect handling can open serious vulnerabilities.
Path Traversal: Attackers may use %2e%2e%2f (the encoded form of ../) to navigate to parent directories on the server. Servers must decode the URL and then validate the resulting path before serving any files.
Cross-Site Scripting (XSS): Script code can be hidden in URL-encoded parameters. When the server outputs URL parameters into HTML, it must apply HTML escaping separately. URL encoding and HTML escaping serve different purposes; forgetting the HTML escape after URL decoding creates a vulnerability.
Open Redirect: An attacker can encode an external URL in a redirect_url parameter, sending users to a phishing site. Always validate redirect URLs against a whitelist of allowed domains.
URL encoding is one of those small things that, when done wrong, leads to hours of debugging. Get it right from the start, and you'll save yourself plenty of headaches.
Frequently Asked Questions
Why is URL encoding necessary?
For detailed information on this topic, please refer to the article above or try our related tools.
What is the difference between encodeURI and encodeURIComponent?
For detailed information on this topic, please refer to the article above or try our related tools.