Skip to content
snip tools

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.