Blog ·
encodeURIComponent vs encodeURI in JavaScript: Which to Use
Use encodeURIComponent for query values and path segments. encodeURI leaves reserved characters like & and / alone, so use it only on a complete URL.
URL Encoder / Decoder
Encode and decode URL/query-string components.
Use encodeURIComponent for any single piece of a URL, such as a query parameter value or a path segment. Use encodeURI only when you have a complete URL and want to escape spaces and non-ASCII characters without breaking its structure. The practical difference is that encodeURI leaves characters like &, =, /, ? and # unencoded, because those characters have meaning in a URL.
If you want to see the output for a specific string before you write any code, paste it into the URL Encoder / Decoder. It runs in your browser and shows the percent-encoded result immediately.
What each function encodes
Both functions convert characters to UTF-8 bytes and write each byte as %XX. They differ in which characters they skip. Characters in the "unreserved" set are never encoded by either function: letters, digits, and the marks - _ . ! ~ * ' ( ).
encodeURI also skips these reserved characters, so they pass through unchanged:
- ; , / ? : @ & = + $ #
encodeURIComponent encodes all of those reserved characters. The only things it leaves alone are the unreserved set above.
Here is the difference on a few inputs:
encodeURI('a b&c=d/e') // 'a%20b&c=d/e'
encodeURIComponent('a b&c=d/e') // 'a%20b%26c%3Dd%2Fe'
encodeURI('https://example.com/search?q=a b&lang=en')
// 'https://example.com/search?q=a%20b&lang=en'
encodeURIComponent('café')
// 'caf%C3%A9'
encodeURI('100%')
// '100%25'Notice that encodeURI does encode the % sign in '100%' as %25, but it does not encode the reserved characters. That is the part that causes bugs when you pass a value through it.
Which one to use
The rule is simple. Ask whether the string you are encoding is a whole URL or a piece of one.
- Query parameter value: use encodeURIComponent. A value containing & or = would otherwise start a new parameter.
- Path segment, such as a file name or ID: use encodeURIComponent. A value containing / would otherwise add a path level.
- Complete URL built from a trusted template with no pre-encoded parts: encodeURI can escape spaces and non-ASCII characters without touching the URL structure. Do not run it over text that is already percent-encoded, because it encodes every % as %25. A value of a%20b becomes a%2520b.
In practice, most code should call encodeURIComponent on each dynamic value and then join the pieces with literal separators:
const term = 'fish & chips';
const page = 2;
const url = `https://api.example.com/search?q=${encodeURIComponent(term)}&page=${encodeURIComponent(page)}`;
// 'https://api.example.com/search?q=fish%20%26%20chips&page=2'The bug that encodeURI causes
The most common mistake is using encodeURI on a query value. Here the search term contains an ampersand:
const term = 'salt & pepper';
const bad = `https://example.com/search?q=${encodeURI(term)}`;
// 'https://example.com/search?q=salt%20&%20pepper'
// The server reads q='salt ' and a separate parameter ' pepper' with no value.
const good = `https://example.com/search?q=${encodeURIComponent(term)}`;
// 'https://example.com/search?q=salt%20%26%20pepper'The bad URL is still valid percent-encoding, so nothing throws. The server just receives the wrong data, which makes this bug easy to miss in testing.
Decoding
The decoding functions mirror the encoders. decodeURIComponent reverses encodeURIComponent for any input it produced. decodeURI reverses encodeURI, but it does not decode escapes for reserved characters, so it can leave %26 in place.
decodeURIComponent('fish%20%26%20chips') // 'fish & chips'
decodeURI('fish%20%26%20chips') // 'fish %26 chips'For query values, use decodeURIComponent. Using decodeURI on a value that contains an escaped & or = gives you a string that still looks encoded.
Common pitfalls
Plus signs and spaces
encodeURIComponent encodes a space as %20 and a plus sign as %2B. HTML form submissions and URLSearchParams use a different convention: they write a space as +. Both are valid in query strings, but they are not interchangeable in every decoder. If your server expects form encoding, use URLSearchParams:
const params = new URLSearchParams({ q: 'a b+c' });
params.toString() // 'q=a+b%2Bc'Lone surrogates throw
encodeURI and encodeURIComponent throw a URIError when the input contains an unpaired UTF-16 surrogate, such as '\uD800'. This usually comes from slicing a string in the middle of an emoji. Normalization does not fix this, because normalization works on valid characters and leaves lone surrogates in place. You have to replace them explicitly. Where it is available, String.prototype.toWellFormed() replaces each lone surrogate with U+FFFD (the replacement character), and you can encode the result safely:
try {
encodeURIComponent('\uD800');
} catch (e) {
console.log(e.name, e.message); // URIError URI malformed
}
const clean = 'emoji \uD83D'.toWellFormed(); // 'emoji \uFFFD'
encodeURIComponent(clean); // 'emoji%20%EF%BF%BD'Check MDN for toWellFormed() support in the runtimes you target. If it is not available, you need to write your own replacement for unpaired surrogates before encoding. Also fix the source of the problem where you can, such as slicing by code point instead of by UTF-16 code unit.
Double encoding
If a value is already encoded and you encode it again, every % becomes %25. A value of a%20b turns into a%2520b. Encode raw values once, at the point where you build the URL, and keep the encoded string out of your data model.
Encoding path segments
Use encodeURIComponent on each segment, not on the full path. A file name like report 2024/final.pdf should become report%202024%2Ffinal.pdf when it is a single segment. Encoding the full path with encodeURI would leave the slash in place, and the server would treat it as a directory separator.
Python note
Python's standard library has the same split. urllib.parse.quote encodes by default and keeps / unencoded, which is closer to encodeURI for paths. Pass safe='' to encode the slash too, which matches encodeURIComponent for a single segment. Check the documentation for the exact default set before relying on it.
FAQ
Is encodeURIComponent safe to use on an entire URL?
No. It will encode the :// after the scheme and the slashes in the path, which breaks the URL. Build the URL from parts instead, and encode only the dynamic values.
Why does encodeURI leave a plus sign alone?
Plus is a reserved character in the URL spec, so encodeURI treats it as meaningful. In query strings, a plus is commonly read as a space, which is why encodeURIComponent encodes it as %2B.
Do these functions encode the apostrophe?
No. Both functions leave ' unencoded, along with ( ) * ! ~. These characters are allowed in URLs, so encoding them is optional for most servers.
Should I use escape() instead?
No. escape() is deprecated and encodes characters differently, including non-ASCII characters that are not UTF-8. Use encodeURIComponent for query values and encodeURI for complete URLs.
URL Encoder / Decoder
Encode and decode URL/query-string components.