``
Enter fullscreen mode Exit fullscreen mode
Notice that & gets encoded to %26. That matters β an unencoded & in a query value would be parsed as a new parameter separator, breaking your URL.
2. encodeURI() β Encode a full URL
This function leaves URL-structural characters (/, :, ?, &, =, #) alone, because it assumes you're encoding an already-formed URL and don't want to break its structure.
const url = "https://example.com/path with spaces/page?key=value";
encodeURI(url);
// β https://example.com/path%20with%20spaces/page?key=value
Enter fullscreen mode Exit fullscreen mode
Rule of thumb: encodeURIComponent for values, encodeURI for whole URLs.
The Decoding Side: decodeURIComponent()
When you read query parameters from a URL, they're already encoded. You need to decode them before use:
const params = new URLSearchParams(window.location.search);
const q = params.get("q"); // URLSearchParams decodes automatically
// Manual approach:
const raw = "%48%65%6C%6C%6F"; // "Hello"
console.log(decodeURIComponent(raw)); // β Hello
Enter fullscreen mode Exit fullscreen mode
URLSearchParams handles decoding automatically, which is why it's worth using over manual string splitting.
Common Mistakes
Encoding the whole URL twice
// Wrong β double-encoding the already-encoded URL
fetch(encodeURIComponent("https://api.example.com/data?key=value"));
// Right β only encode the value part
const key = encodeURIComponent("my value with spaces");
fetch(`https://api.example.com/data?key=${key}`);
Enter fullscreen mode Exit fullscreen mode
Double-encoding turns %20 into %2520 (because % β %25). The server decodes once and gets %20 literally, not a space.
Using + instead of %20
HTML forms encode spaces as + in application/x-www-form-urlencoded bodies. URL encoding uses %20. The two formats are not interchangeable in all contexts:
%20 is always safe in URLs
+ works in query strings on servers that parse application/x-www-form-urlencoded, but not in path segments
When in doubt, use %20 (i.e., use encodeURIComponent).
Forgetting non-ASCII characters
If you're building a URL with user input that might include accented characters, emoji, or any non-Latin script, you must encode it. encodeURIComponent handles this correctly β it UTF-8 encodes the character first, then percent-encodes each byte.
encodeURIComponent("cafΓ©"); // β "caf%C3%A9"
encodeURIComponent("ζ₯ζ¬θͺ"); // β "%E6%97%A5%E6%9C%AC%E8%AA%9E"
encodeURIComponent("π"); // β "%F0%9F%9A%80"
Enter fullscreen mode Exit fullscreen mode
A Real-World Example: Building a Search URL
Imagine you're building a "Search on Wikipedia" link from user input:
function wikiLink(query) {
return `https://en.wikipedia.org/wiki/Special:Search?search=${encodeURIComponent(query)}`;
}
wikiLink("C++ programming language");
// β https://en.wikipedia.org/wiki/Special:Search?search=C%2B%2B%20programming%20language
Enter fullscreen mode Exit fullscreen mode
Notice + in C++ becomes %2B. Without encoding, the server would interpret + as a space.
When You Need to Encode/Decode Quickly
For one-off encoding and decoding during development β converting a value, checking what a percent-encoded string says, or generating a URL hash β a browser-based tool is faster than switching to a Node.js REPL. I use the URL Encoder/Decoder at SnappyTools for this. Paste in a value, get the encoded form, done. No signup, 100% client-side.
Summary
- URL encoding replaces unsafe characters with
% + two hex digits
encodeURIComponent() β encode a value (encodes &, =, /, +, etc.)
encodeURI() β encode a complete URL (leaves structural characters intact)
URLSearchParams β the cleanest way to build and parse query strings in modern JavaScript
- Non-ASCII characters are UTF-8 encoded first, then percent-encoded byte by byte
- Never encode the same string twice β you'll get
%2520 instead of %20
Get the encoding right once and you'll never waste an afternoon debugging a mysteriously broken API call again.