URL Encoding Explained: What is %20 and Why Does It Exist?
If you've ever copied a URL with spaces in it, you've seen %20. URLs can only contain a limited set of characters — anything else must be "percent encoded." This guide explains the why and how.
Why URLs can't contain spaces
The URL specification (RFC 3986) defines which characters are safe to use in a URL. Only letters, digits, and a handful of symbols — -, _, ., ~ — are "unreserved" and can appear as-is. Everything else has special meaning (like /, ?, &, =) or is simply not allowed (like spaces, quotes, and Unicode characters).
When you need to include an "unsafe" character in a URL — say, a search query with spaces — it must be encoded as its hexadecimal byte value preceded by a percent sign.
How percent encoding works
Every character has a numeric code in the ASCII (or UTF-8) standard. The space character is ASCII code 32, which is 20 in hexadecimal. So a space becomes %20. The at-sign (@) is ASCII 64, hex 40, so it becomes %40.
Original: https://example.com/search?q=hello world&lang=en Encoded: https://example.com/search?q=hello%20world&lang=en
Most common encoded characters
| Character | Encoded | Name |
|---|---|---|
| space | %20 | Space (also + in form data) |
| ! | %21 | Exclamation mark |
| # | %23 | Hash (fragment identifier) |
| & | %26 | Ampersand (separates query params) |
| ' | %27 | Single quote |
| + | %2B | Plus sign |
| / | %2F | Forward slash (path separator) |
| : | %3A | Colon |
| = | %3D | Equals (key=value separator) |
| ? | %3F | Question mark (query start) |
| @ | %40 | At sign |
| % | %25 | Percent sign itself |
Encoding in JavaScript: encodeURI vs encodeURIComponent
JavaScript has two built-in functions, and choosing the wrong one is a common source of bugs:
encodeURI()— encodes a full URL. Leaves characters like/,?,&,=intact because they are structural parts of a URL.encodeURIComponent()— encodes a URL component (a query parameter value). Encodes everything including/,?,&,=. Use this for values being inserted into a URL.
// encodeURI — for full URLs
encodeURI("https://example.com/search?q=hello world");
// "https://example.com/search?q=hello%20world"
// Notice: ?, =, / are preserved
// encodeURIComponent — for values within URLs
encodeURIComponent("hello world & more");
// "hello%20world%20%26%20more"
// Notice: & is encoded to %26
// Building a URL safely:
const query = "cats & dogs";
const url = `https://example.com/search?q=${encodeURIComponent(query)}`;
// "https://example.com/search?q=cats%20%26%20dogs"
// Decoding:
decodeURIComponent("hello%20world") // "hello world"URL encoding in other languages
# Python
from urllib.parse import quote, unquote, urlencode
quote("hello world") # "hello%20world"
unquote("hello%20world") # "hello world"
urlencode({"q": "hello world", "lang": "en"})
# "q=hello+world&lang=en"
# PHP
urlencode("hello world") // "hello+world"
rawurlencode("hello world") // "hello%20world"
# curl
curl "https://example.com/search?q=hello%20world"%20 vs + for spaces
In URL query strings specifically, a space can be encoded as either %20 or +. The + encoding comes from HTML form submission (application/x-www-form-urlencoded format). Both are valid in query strings — but outside of query strings (in paths, for example), only %20 is correct. encodeURIComponent() always uses %20, which is the safer choice.
Encode or decode any URL instantly — with a bonus query string parser that breaks down all parameters.
Open URL Encoder →