URL Encode / Decode
Percent-encoding conversion for Chinese parameters and special characters
URL encoding, decoded: encodeURI vs encodeURIComponent and the five mistakes that bite most
Why URL encoding exists
The URL character set is deliberately tiny — RFC 3986 permits only a subset of ASCII. Any character outside that set — a space, a Chinese character, &, ?, # — must first be rewritten as percent-encoding: a % followed by two hexadecimal digits. This is the language browsers and servers use so that a URL means exactly one thing end to end.
The part people get wrong: non-ASCII characters must be UTF-8 encoded into bytes first, then each byte is percent-encoded separately. The Chinese character for "middle," 中, has UTF-8 bytes E4 B8 AD, so its encoding is %E4%B8%AD — not a single byte value. Encoding by some other charset such as GBK is the classic root cause of mojibake.
Within RFC 3986 the allowed characters split into two camps: unreserved characters (letters, digits, and a small set of marks) that never need encoding, and reserved characters that carry structural meaning and must be encoded whenever they appear outside that meaning. The percent sign itself is the escape indicator, which is exactly why encoding a percent sign produces %25 rather than leaving it untouched.
The difference between encodeURI and encodeURIComponent
This is the choice most likely to be wrong in real code, because the two functions keep different character sets unescaped:
| Characters left unescaped | encodeURI | encodeURIComponent |
|---|---|---|
| letters and digits | yes | yes |
- _ . ! ~ * ' ( ) | yes | yes |
structural chars ; , / ? : @ & = + $ # | yes | no |
The rule is simple:
- Encoding a whole URL — for example, passing one address as a parameter to another system — use
encodeURI. Otherwisehttps://turns intohttps%3A%2F%2Fand the link dies. - Encoding a value inside a URL — a query parameter's value, a path segment — use
encodeURIComponent. Otherwise an&in the value is parsed as a parameter separator and the rest gets sliced off.
The classic production bug: a search term of a&b passed through encodeURI stays a&b and reaches the server intact, which then reads it as two parameters — q=a and b=. The correct fix is encodeURIComponent, giving a%26b.
A useful mental model is that encodeURI assumes the string already is a URL and should remain a working URL, while encodeURIComponent assumes the string is a single value that must be dropped safely into one slot of a URL. Reaching for the wrong one is the difference between a link that works and a parameter that silently loses half its content.
Spaces: %20 or +
Both forms exist, but they belong in different places:
%20is the URL-standard encoding of a space and is legal in any position.+only means a space inside the query string of anapplication/x-www-form-urlencodedform submission. It belongs to the HTML form spec, not the URL spec.
So a + in a path is a literal plus, not a space. Decoding /a+b/ as /a b/ is a mistake. This tool lets you pick %20 or + depending on the context and shows both results side by side so you can compare.
Five pitfalls worth committing to memory
- Double encoding. Encoding twice yields
%2520, because the%itself becomes%25. Spotting%25should raise an alarm that an extra layer slipped in. The test: decode once and see whether the result becomes another valid percent sequence. - Encoding the value but not the key. Parameter names can contain special characters too; both sides need encoding.
- Forgetting to encode
&and=. This is the entry point for injection-class bugs and the root of parameter confusion. - Assuming the server decodes automatically. It may not. Frameworks, API gateways, and CDNs each may decode one layer or none at all. Agree on the convention before you send.
- Encoding
#to%23but still expecting an anchor. Once encoded,%23is a literal character, no longer a fragment identifier.
These pitfalls share a single root cause: percent-encoding is a contract between sender and receiver, and the contract only holds when both sides agree on how many layers of encoding are in play. When a value travels through a proxy, a web framework, and a CDN, each step may add or remove one layer, and the only way to stay correct is to encode exactly once at the boundary you control and decode at the boundary the receiver controls.
Quick reference for common characters
| Character | Encoding | Note |
|---|---|---|
| space | %20 | standard; + in form context |
& | %26 | parameter separator, must encode in values |
= | %3D | key-value separator, must encode in values |
? | %3F | starts the query string |
# | %23 | starts the fragment |
+ | %2B | left unencoded it reads as a space |
% | %25 | the encoding prefix escapes itself |
| Chinese | one %XX per byte | UTF-8 first, then byte by byte |
The tool supports one-way encoding, one-way decoding, and bidirectional conversion; you can paste either a full URL or bare text and it will handle both.
FAQ
What is the difference between encodeURI and encodeURIComponent?
The former keeps URL structural characters like / ? & = and suits a full URL; the latter escapes everything and suits parameter values. This tool uses the latter.