encodeURIComponent vs encodeURI: URL Encoding Explained
encodeURI is for a whole URL, encodeURIComponent is for one value inside it. See what each escapes, why + becomes a space, and how to avoid double encoding.
JavaScript has two built-in functions for percent-encoding, and picking the wrong one is one of the most common URL bugs. encodeURI is for a whole URL. encodeURIComponent is for one piece of a URL, such as a single query value or path segment. Use the first on a value and its & or = breaks your query string. Use the second on a whole URL and the :// and / get escaped too.
You can try both modes below on your own input. Everything runs in your browser, so nothing you paste is uploaded.
URL Encoder & DecoderPercent-encode text for use in a URL, or decode it back. Choose whether you are encoding one query value or an entire URL, because the two need different escaping.What percent-encoding does
A URL can only contain a limited set of ASCII characters, and some of them have a structural meaning: / separates path segments, ? starts the query, & separates parameters, = splits a key from its value and # starts the fragment. Any character that is not allowed, or that would be mistaken for one of these separators, is written as % followed by the hex value of each of its UTF-8 bytes.
space → %20
& → %26
é → %C3%A9 (two UTF-8 bytes)
☕ → %E2%98%95 (three UTF-8 bytes)
The difference in one example
Take a URL with a search term that contains &:
const url = 'https://example.com/search?q=rock & roll&lang=en#top';
encodeURI(url);
// https://example.com/search?q=rock%20&%20roll&lang=en#top
encodeURIComponent(url);
// https%3A%2F%2Fexample.com%2Fsearch%3Fq%3Drock%20%26%20roll%26lang%3Den%23top
encodeURI kept the URL usable but left the & inside "rock & roll" alone, so the server now sees a parameter called roll and the search term is just rock . encodeURIComponent escaped everything, including the :// and /, so the result is no longer a URL at all. Neither call produced the right answer, because the input mixed structure and data. The fix is to encode only the data:
const q = 'rock & roll';
const url = `https://example.com/search?q=${encodeURIComponent(q)}&lang=en`;
// https://example.com/search?q=rock%20%26%20roll&lang=en
Which characters each function leaves alone
| Characters | encodeURIComponent | encodeURI |
|---|---|---|
A-Z a-z 0-9 - _ . ! ~ * ' ( ) | kept | kept |
; , / ? : @ & = + $ # | escaped | kept |
Space, quotes, < > and non-ASCII | escaped | escaped |
% | escaped to %25 | escaped to %25 |
The second row is the whole story. encodeURI assumes those characters are structure and leaves them in place; encodeURIComponent assumes they are data and escapes them.
Rule of thumb
- Building a URL from parts: run
encodeURIComponenton each value, never on the parts you typed yourself. - Cleaning up a complete URL that has spaces or non-ASCII in it:
encodeURIis acceptable, but only if the URL's own data is already encoded correctly. - In modern code: let
URLandURLSearchParamsdo it for you.
const u = new URL('https://example.com/search');
u.searchParams.set('q', 'rock & roll');
u.searchParams.set('next', '/a?b=1');
u.href;
// https://example.com/search?q=rock+%26+roll&next=%2Fa%3Fb%3D1
Why a space is sometimes +
URLSearchParams wrote the space as +, not %20. That comes from HTML form encoding (application/x-www-form-urlencoded), which is what browsers send when a form is submitted. In a query string both forms mean a space, but the decoders do not agree:
decodeURIComponent('a+b'); // "a+b"
new URLSearchParams('q=a+b').get('q'); // "a b"
So if you decode a form-style query string with decodeURIComponent, spaces come back as literal + signs. The reverse bug is worse: a real + in a value, such as a phone number like +62 812, must be sent as %2B, or a form decoder turns it into a space. encodeURIComponent and URLSearchParams both do this correctly; hand-built strings often do not.
Common errors
- Double encoding. Encoding a value that is already encoded turns
%into%25, so a space shows up as%2520. Encode once, at the point where the value goes into the URL, and decode once where it comes out. URIError: URI malformed.decodeURIComponent('100%')throws, because a%must be followed by two hex digits. A stray%or a truncated multi-byte sequence like%E4%B8both cause it. Wrap decoding intry/catchwhen the input is user supplied.- Broken redirects. A
nextorredirect_uriparameter that holds another URL must be encoded withencodeURIComponent, or its own?and&merge into the outer query string. - Garbled non-English text. Percent-encoding works on UTF-8 bytes. Older systems that decode as Latin-1 turn
%C3%A9intoéinstead ofé. - Characters
encodeURIComponentskips. It leaves! ' ( ) *alone. They are legal in URLs, but a few strict APIs (some OAuth 1.0 signatures, for example) require them escaped as well.
Percent-encoding is not Base64URL
Both make data safe for URLs, but they solve different problems. Percent-encoding keeps readable text mostly readable and escapes only the characters that need it. Base64URL turns arbitrary bytes, including binary data, into a compact string that uses only URL-safe characters, at the cost of making it unreadable. If you are putting a token or binary blob into a URL, Base64URL is usually the better fit; for search terms, names and paths, use percent-encoding.
Base64 Encoder & DecoderEncode text to Base64 or decode it back. Unicode is handled correctly, so Japanese, Chinese, Korean and emoji all round-trip without corruption.If the finished URL needs to be scanned from a phone or a printed page, you can turn it into a QR code once it is encoded correctly.
QR Code GeneratorGenerate a QR code for a URL, text or Wi-Fi network and download it as PNG or SVG. Everything happens in your browser, so nothing is uploaded and the code never expires.