URL Encoding Explained: Which Characters to Escape and Why
By Junaid Aslam. 4 min read. Updated .
Copy a link and you may find it full of %20 and %3D. That's URL encoding, also called percent-encoding. The rule is simple. Some characters have a job inside a URL. If you want to use one of them as plain data, you have to escape it so the browser doesn't mistake it for punctuation.
How percent-encoding works
A URL can only safely carry a small set of characters. Anything outside that set gets replaced by a percent sign followed by two hex digits. Those two digits are the byte value. A space is byte 32, which is hex 20, so it becomes %20.
For characters outside basic ASCII, the text is first converted to UTF-8 bytes, and each byte gets its own percent code. The letter é is two bytes in UTF-8 (C3 A9), so it becomes %C3%A9. Emoji take four bytes, so they turn into four percent groups.
Safe characters, reserved characters
RFC 3986, the standard that defines URLs, splits characters into two groups.
- Unreserved (never need escaping): letters
A-Zanda-z, digits0-9, and the four symbols-._~. - Reserved (have a special meaning):
: / ? # [ ] @ ! $ & ' ( ) * + , ; =.
Reserved characters are fine when they're doing their job. The ? starts the query string, & separates parameters, and = joins a name to its value. The trouble starts when one of them appears inside your data. If a search term contains &, you must escape it, or the server will think a new parameter began.
The ones you'll hit most often
| Character | Encoded | Why it matters |
|---|---|---|
| Space | %20 | Spaces aren't allowed in URLs at all. |
& | %26 | Would start a new query parameter. |
= | %3D | Would split a name from its value. |
? | %3F | Would start the query string early. |
# | %23 | Would start the fragment and cut off the rest. |
/ | %2F | Would add a new path segment. |
+ | %2B | Often read as a space in query strings. |
% | %25 | The escape character itself must be escaped. |
@ | %40 | Separates user info from host. |
: | %3A | Separates scheme, port, and user info. |
%20 or +? Both show up for spaces
This confuses everyone at some point. In the path part of a URL, a space is always %20. In HTML form submissions (the application/x-www-form-urlencoded format), a space is often written as +. Servers that parse query strings usually understand both. But if you send a literal plus sign as data, you must write %2B, or the server will read it as a space. That's a classic bug when people pass phone numbers like +15551234567 or Base64 strings in a query.
encodeURI vs encodeURIComponent
JavaScript gives you two functions, and picking the wrong one causes a lot of broken links.
encodeURIComponentescapes nearly everything, including/ ? & = #. Use it on a single value that goes inside a URL, like one query parameter.encodeURIleaves reserved characters alone so a full URL still works. Use it only when you're encoding a whole address that's already structured correctly.
The same input through both:
encodeURI("a b+c/d?e#f&g=h")
// a%20b+c/d?e#f&g=h
encodeURIComponent("100% & more")
// 100%25%20%26%20moreencodeURI kept +, /, ?, #, &, and = untouched. If you'd used it on a search term containing &, that term would break your query. When in doubt for parameter values, use encodeURIComponent.
The double-encoding trap
Encode a string twice and the percent signs themselves get escaped. %20 becomes %2520, because % turned into %25. You'll see this when a value passes through two layers of code that each think they're responsible for encoding. Symptoms are links that show %2520 in the address bar, or a server that receives the literal text %20 instead of a space.
The fix is to encode exactly once, at the last moment before the value goes into the URL, and decode exactly once on the other side. The URL Encoder can help you check. Decode once and see whether %20 shows up where you expected a space. If it does, something encoded the value twice. Its Double encode/decode box runs the operation twice in one click when you need to undo that.
Quick checklist
- Encode each parameter value separately, not the whole finished URL.
- Use UTF-8 for anything that isn't plain ASCII.
- Escape
+as%2Bwhen you mean a real plus sign. - Never encode the same string twice.
- If a link works in one browser and not another, check for an unescaped
#or&first.
Moving a Base64 or hash value through a URL? You'll want to read our notes on Base64 and why + and / cause trouble.