URL Encoding Special Characters: The Complete Guide
Every developer eventually gets burned by URL encoding. A user searches for "cats & dogs", your redirect turns into a broken link, and a callback URL silently drops half its query string. This guide covers what percent-encoding actually is, which characters need it, and the correct JavaScript function for each situation.
What is percent-encoding?
URLs are limited to a small subset of ASCII. Anything outside that set — spaces, non-Latin letters, punctuation with special meaning — has to be replaced with a % followed by the character's UTF-8 byte in hex. A space becomes %20, an ampersand becomes %26, and an emoji like 🎉 becomes %F0%9F%8E%89 (four bytes, four percent-hex pairs).
The rules come from RFC 3986. Two categories matter:
- Reserved characters —
: / ? # [ ] @ ! $ & ' ( ) * + , ; =— have syntactic meaning inside URLs. Encode them when they appear in data, leave them alone when they're structural. - Unreserved characters — letters, digits, and
- _ . ~— never need encoding.
encodeURI vs encodeURIComponent — the one that trips everyone up
JavaScript ships two encoders and they do different jobs:
encodeURI(url)— encodes a whole URL and leaves reserved characters alone. Use it when you have a URL that just has spaces or non-ASCII in it.encodeURIComponent(value)— encodes a single value that will be inserted into a URL. It also encodes& = ? #, so it's safe for query-string values.
const query = "cats & dogs";
const badUrl = "https://example.com/search?q=" + query;
// → https://example.com/search?q=cats & dogs ❌ breaks the query
const goodUrl = "https://example.com/search?q=" + encodeURIComponent(query);
// → https://example.com/search?q=cats%20%26%20dogs ✅
The +, space, and application/x-www-form-urlencoded gotcha
HTML forms encode spaces as +, not %20. That's a legacy of the pre-URL world. The two are equivalent inside query strings but not inside a path. Confusion arises when a value comes in with a literal + character:
const email = "alice+work@example.com";
const params = new URLSearchParams({ email });
console.log(params.toString());
// → email=alice%2Bwork%40example.com ✅
// vs
const bad = "email=" + encodeURIComponent(email);
// Also correct — encodeURIComponent encodes + as %2B.
Use URLSearchParams whenever you're building query strings — it handles the + versus %20 difference correctly and joins everything with &.
When to encode paths vs query vs fragment
- Path segments — encode
/if it's part of the value (a filename with a slash), leave it if it separates segments. UseencodeURIComponentfor each segment and join with/. - Query parameters — always
encodeURIComponentboth key and value. Or better, useURLSearchParams. - Fragment (
#...) — encode spaces and reserved characters.encodeURIComponentis safe.
Common characters and their encodings
| Character | Encoded | Why |
|---|---|---|
| space | %20 or + | Not allowed literally. |
& | %26 | Separates query params. |
= | %3D | Splits key from value. |
# | %23 | Starts the fragment. |
? | %3F | Starts the query string. |
+ | %2B | Means space in form-encoding. |
/ | %2F | Separates path segments. |
é | %C3%A9 | Non-ASCII → UTF-8 bytes. |
Test any string right now
Paste any URL or value into the URL Encoder & Decoder to see the encoded and decoded versions side by side, plus a breakdown of the parsed URL parts. Runs entirely in your browser.
Keep reading
How to Format JSON in JavaScript (2026 Guide)
Learn every practical way to format, pretty-print, indent, and validate JSON in JavaScript — with copy-paste examples for Node.js and the browser.
Base64 Encoding Explained: What It Is and When to Use It
Base64 in one plain-English guide: how it works, when to use it, when NOT to, and how to encode and decode it in every major language.