URL Encoding Explained: When and Why You Need It
Understand URL encoding, percent-encoding, why spaces become %20, and when to encode your URLs. Includes practical examples in JavaScript, Python, and bash.
Try it yourself
Use our free URL Encoder — no sign-up, runs in your browser.
URLs have a specific format. Certain characters are reserved for special meaning - slashes separate paths, question marks introduce query parameters, ampersands separate parameters. But what happens when your data contains these characters? Or spaces? That’s where URL encoding comes in.
Why URL encoding exists
URLs can only contain a limited set of characters safely. Reserved characters like ?, &, #, and spaces need special handling.
Compare these:
// Regular text
search for: "hello world"
// In a URL query string (wrong)
https://example.com/search?q=hello world
// Problem: spaces break the URL
// In a URL query string (correct)
https://example.com/search?q=hello%20world
// Works: %20 represents a space
The browser interprets the first URL incorrectly. The second one works because spaces are “percent-encoded” as %20.
What is percent-encoding?
Percent-encoding (also called URL encoding) converts characters to a % followed by two hexadecimal digits.
| Character | Encoded | Hex Value |
|---|---|---|
| space | %20 | 0x20 |
! | %21 | 0x21 |
# | %23 | 0x23 |
$ | %24 | 0x24 |
& | %26 | 0x26 |
? | %3F | 0x3F |
= | %3D | 0x3D |
The hexadecimal value maps to the character’s ASCII code. Space (ASCII 32) is 0x20 in hex, so it encodes as %20.
When to encode URLs
You need to encode:
- Query string parameters (the value part after
?) - Path segments containing special characters
- Form data in request bodies
You don’t encode:
- The protocol (
https://) - The domain name
- The forward slashes separating path segments (unless they’re in data)
https://example.com/search?q=hello%20world&filter=active
└─────┬─────┘ └───┬──┘ └───────────────────┬──────────────┘
Protocol & domain Path Query string (encoded)
Encoded: query value and parameter names
Not encoded: scheme, domain, path slashes
Reserved characters that need encoding
These characters have special meaning in URLs and must be encoded in certain contexts:
: / ? # [ ] @ ! $ & ' ( ) * + , ; = %
For example:
&separates query parameters, so if your data contains&, encode it as%26=separates parameter names from values, so if your value contains=, encode it as%3D#starts a fragment, so if your data contains#, encode it as%23
Encoding in JavaScript
Use encodeURIComponent() for query string values and encodeURI() for full URLs:
// Encoding a query parameter value
const userInput = "John Doe & Friends";
const encoded = encodeURIComponent(userInput);
console.log(encoded);
// Output: John%20Doe%20%26%20Friends
// Building a query string
const name = "Product & Services";
const query = `?q=${encodeURIComponent(name)}`;
console.log(query);
// Output: ?q=Product%20%26%20Services
// Decoding
const decoded = decodeURIComponent("John%20Doe%20%26%20Friends");
console.log(decoded);
// Output: John Doe & Friends
Use encodeURIComponent() for:
- Query parameter values
- Form field values
- Anything that’s data, not structure
Use encodeURI() sparingly - it encodes less aggressively and is meant for full URLs, not individual values.
Encoding in Python
from urllib.parse import quote, unquote, urlencode
# Encode a single string
text = "hello world & friends"
encoded = quote(text)
print(encoded)
# Output: hello%20world%20%26%20friends
# Decode
decoded = unquote(encoded)
print(decoded)
# Output: hello world & friends
# Encode query parameters (recommended)
params = {"q": "hello world", "filter": "active"}
query_string = urlencode(params)
print(query_string)
# Output: q=hello+world&filter=active
# Build full URL
from urllib.parse import urljoin
base = "https://example.com/search?"
url = base + query_string
print(url)
# Output: https://example.com/search?q=hello+world&filter=active
Encoding in Bash
# Using printf and sed
text="hello world & friends"
encoded=$(printf %s "$text" | sed 's/ /%20/g' | sed 's/&/%26/g')
echo $encoded
# Output: hello%20world%20%26%20friends
# Better: use a loop for all special characters
urlencode() {
local string="${1}"
printf %s "$string" | jq -sRr @uri
}
urlencode "hello world & friends"
# Output: hello%20world%20%26%20friends
Common encoding gotchas
Space encoding: %20 vs +
In query strings, space can be encoded as %20 (percent-encoded) or + (form-encoded). Both mean the same thing.
https://example.com/search?q=hello%20world ✅
https://example.com/search?q=hello+world ✅ (form-encoded, common in forms)
Use %20 in path segments and when you want to be explicit. Use + in form submissions (browsers do this automatically).
Encoding & - a common mistake
If your parameter value contains &, you must encode it as %26:
// Wrong - parsed as two parameters
?q=fish & chips
// Correct - parsed as one parameter with value "fish & chips"
?q=fish%20%26%20chips
Double-encoding (a security issue)
Don’t encode twice. This is a common bug:
// Wrong - double-encoded
const value = "hello world";
const encoded1 = encodeURIComponent(value); // "hello%20world"
const encoded2 = encodeURIComponent(encoded1); // "hello%2520world"
// %2520 = %25 + "20", where %25 is the % character itself
// Right - encode once
const encoded = encodeURIComponent(value);
When does the browser auto-encode?
Modern browsers auto-encode spaces in URL bars (you can type spaces, they become %20). But programmatically, always encode explicitly - don’t rely on auto-encoding.
Decode URLs and check your work
Use our free URL Encoder to encode and decode URLs online. Paste a URL or text and see exactly what gets encoded and why - helpful for debugging API calls and query strings.
Summary
- Encode query string values, path data, and form data using
encodeURIComponent()(JavaScript) orquote()(Python) - Don’t encode the scheme, domain, or path slashes
- Reserved characters (
&,?,#,=,%, etc.) must be encoded in data values - Space encodes as
%20(or+in forms) - Never double-encode - encode once and use the result
- Test your URLs with a URL encoder tool to catch mistakes early