URL encoding in JavaScript: encodeURIComponent vs encodeURI
A snip.tools guide · runs alongside the URL encode / decode
Prefer to just run it? Use the free URL encode / decode — no install, in your browser.
Open the URL encode / decode
URLs can only contain a limited set of characters, so anything else — spaces, ampersands, accents, slashes
inside a value — has to be percent-encoded (turned into % followed by hex). Get
this wrong and a stray & or ? in your data silently breaks the URL's structure.
JavaScript gives you two encoders that do different jobs, plus a cleaner modern API that you should
usually reach for first. (To encode or decode a string on the spot, use our in-browser
URL encoder / decoder.)
encodeURIComponent: for a single value
Use encodeURIComponent when you're inserting one piece of data — a query value, a path
segment, a fragment — into a URL. It encodes aggressively, escaping every character that has structural
meaning in a URL (&, =, ?, /, #) so your
value can't accidentally be read as part of the URL's grammar:
// encodeURIComponent — for a single value going into a URL.
encodeURIComponent('a&b=c?'); // "a%26b%3Dc%3F"
encodeURIComponent('café / 100%'); // "caf%C3%A9%20%2F%20100%25"
// It percent-encodes everything that isn't unreserved (A-Z a-z 0-9 - _ . ! ~ * ' ( )). encodeURI: for a whole URL
Use encodeURI when you have a complete URL that may contain illegal characters (a
space in a path, say) but whose structure you want to preserve. It deliberately leaves the reserved
characters that separate a URL's parts — :/?&=# — untouched:
// encodeURI — for an entire URL you don't want to break apart.
encodeURI('https://x.com/path with space?q=a&b=c');
// "https://x.com/path%20with%20space?q=a&b=c"
// Note: it left :/?&= alone, because those are structural characters.
That difference is the whole point: encodeURIComponent('a&b') escapes the ampersand because
inside a value it's data, while encodeURI keeps it because between parameters it's a separator.
Picking the wrong one is the classic bug — running a value through encodeURI
leaves its & unescaped, and a value like "rock & roll" then injects a phantom
query parameter.
The better way: URLSearchParams
For query strings specifically, you usually shouldn't call either function by hand. URLSearchParams
encodes each key and value correctly for you, and decodes on the way back — far less error-prone than
concatenating strings:
// The modern, mistake-proof way to build a query string.
const params = new URLSearchParams({
q: 'café & cream',
page: '2',
});
params.toString(); // "q=caf%C3%A9+%26+cream&page=2"
`/search?${params}`; // "/search?q=caf%C3%A9+%26+cream&page=2"
// Reading them back:
const sp = new URLSearchParams('q=caf%C3%A9+%26+cream&page=2');
sp.get('q'); // "café & cream" (decoded for you)
Combine it with the URL constructor for full URLs (const u = new URL('https://x.com');
u.searchParams.set('q', value)) and you essentially can't produce a malformed query string.
Decoding
Each encoder has a matching decoder. Use the one that pairs with how the text was encoded:
decodeURIComponent('caf%C3%A9%20%2F%20100%25'); // "café / 100%"
decodeURI('https://x.com/path%20with%20space'); // "https://x.com/path with space" The +-versus-%20 space gotcha
Spaces have two valid encodings and this trips people up constantly. In a percent-encoded URL component a
space is %20; in application/x-www-form-urlencoded data (HTML form submissions and
URLSearchParams output) a space is +:
// The space gotcha: two valid encodings depending on context.
encodeURIComponent('a b'); // "a%20b" (percent-encoding)
new URLSearchParams({x:'a b'}).toString(); // "x=a+b" (form-encoding: + means space)
// Both decode back to "a b" with the matching decoder — don't mix them by hand.
The rule: don't decode form-style +-as-space text with decodeURIComponent (it will
leave the +), and don't hand-roll either format — let URLSearchParams handle the
pairing. One more thing to skip entirely: the legacy escape() and unescape()
functions are deprecated and don't handle UTF-8 correctly — never use them for URLs.
A note on Unicode
encodeURIComponent is UTF-8 aware: "é" becomes %C3%A9 (its two UTF-8
bytes), which is exactly what servers expect. That's the same UTF-8-first principle behind correctly handling
other encodings — see Base64 in JavaScript for the
parallel story. To percent-encode or decode any string interactively, the
URL encoder / decoder runs entirely in your browser. Related:
HTML entity encoding solves the same "make this text safe" problem for HTML
rather than URLs.
Try it now: the URL encode / decode does everything in this guide in your browser — nothing is uploaded. Browse more guides or the full tool list.