How URL Encoding Works
URL encoding converts unsafe characters into a percent sign followed by two hexadecimal digits representing the character's ASCII value.
The process:
- Identify unsafe characters - Characters that aren't A-Z, a-z, 0-9, or -_.~
- Get the ASCII/UTF-8 value - Convert the character to its numeric code
- Convert to hex - Express the value in hexadecimal
- Add percent sign - Prefix with %
Examples:
- Space (ASCII 32) → %20
- Ampersand (ASCII 38) → %26
- Question mark (ASCII 63) → %3F
- @ sign (ASCII 64) → %40
Reserved characters that have special meaning in URLs:
!#$&'()*+,/:;=?@[]
These MUST be encoded when used in data values (not as URL structure).
When to Use URL Encoding
URL encoding is essential in many scenarios:
1. Query String Parameters
When passing data in URLs:
https://example.com/search?q=hello%20world&category=books%26music
2. Form Submissions
HTML forms with method="GET" URL-encode the data automatically.
3. API Requests
Building URLs for REST APIs with dynamic parameters.
4. File Paths with Spaces
URLs to files with spaces or special characters:
https://example.com/files/my%20document.pdf
5. Email Links (mailto)
Encoding subject and body parameters:
mailto:user@example.com?subject=Hello%20World&body=Hi%20there
6. OAuth & Authentication
Encoding redirect URLs and tokens.
encodeURIComponent vs encodeURI
JavaScript provides two URL encoding functions with different use cases:
encodeURIComponent()
- Encodes ALL special characters including /, ?, &, =, #
- Use for: Query parameter VALUES
- Example:
name=${encodeURIComponent(value)}
encodeURI()
- Preserves URL structure characters
- Use for: Encoding entire URLs while keeping them valid
- Example:
encodeURI("https://example.com/path with spaces")
Critical difference:
// encodeURIComponent - encodes EVERYTHING
const value = "name=John&city=NYC";
console.log(encodeURIComponent(value));
// "name%3DJohn%26city%3DNYC"
// encodeURI - preserves URL structure
console.log(encodeURI(value));
// "name=John&city=NYC" (unchanged!)
// Real-world example: building a URL
const searchTerm = "cats & dogs";
const url = "https://api.example.com/search";
// ✅ CORRECT: encode the parameter value
const correctUrl = `${url}?q=${encodeURIComponent(searchTerm)}`;
// "https://api.example.com/search?q=cats%20%26%20dogs"
// ❌ WRONG: would break the URL structure
const wrongUrl = encodeURIComponent(`${url}?q=${searchTerm}`);
// "https%3A%2F%2Fapi.example.com%2Fsearch%3Fq%3Dcats%20%26%20dogs"URL Encoding in JavaScript
JavaScript provides several built-in functions for URL encoding:
// Encode a parameter value
const value = "Hello World! @#$%";
const encoded = encodeURIComponent(value);
console.log(encoded); // "Hello%20World!%20%40%23%24%25"
// Decode back
const decoded = decodeURIComponent(encoded);
console.log(decoded); // "Hello World! @#$%"
// Build a complete URL with parameters
function buildUrl(base, params) {
const query = Object.entries(params)
.map(([key, value]) =>
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
)
.join('&');
return `${base}?${query}`;
}
const url = buildUrl('https://api.example.com/search', {
q: 'cats & dogs',
page: '1',
filter: 'name=fluffy'
});
// "https://api.example.com/search?q=cats%20%26%20dogs&page=1&filter=name%3Dfluffy"
// Using URLSearchParams (modern approach)
const params = new URLSearchParams();
params.append('q', 'cats & dogs');
params.append('page', '1');
console.log(params.toString());
// "q=cats+%26+dogs&page=1"URL Encoding in Python
Python's urllib.parse module handles URL encoding:
from urllib.parse import quote, unquote, urlencode
# Encode a string
text = "Hello World! @#$%"
encoded = quote(text)
print(encoded) # "Hello%20World%21%20%40%23%24%25"
# Decode back
decoded = unquote(encoded)
print(decoded) # "Hello World! @#$%"
# Encode with safe characters (won't encode these)
path = "/path/to/file"
encoded_path = quote(path, safe='/')
print(encoded_path) # "/path/to/file" (slashes preserved)
# Build query string from dictionary
params = {
'q': 'cats & dogs',
'page': '1',
'filter': 'name=fluffy'
}
query_string = urlencode(params)
print(query_string)
# "q=cats+%26+dogs&page=1&filter=name%3Dfluffy"
# For proper percent-encoding (not +), use quote_plus
from urllib.parse import quote_plus
encoded = quote_plus("hello world")
print(encoded) # "hello+world"Common URL Encoding Reference
Here are the most commonly encoded characters:
| Character | Encoded | Description |
|---|---|---|
| (space) | %20 | Space character |
| ! | %21 | Exclamation mark |
| " | %22 | Double quote |
| # | %23 | Hash (fragment) |
| $ | %24 | Dollar sign |
| % | %25 | Percent sign |
| & | %26 | Ampersand |
| ' | %27 | Single quote |
| ( | %28 | Open parenthesis |
| ) | %29 | Close parenthesis |
| * | %2A | Asterisk |
| + | %2B | Plus sign |
| , | %2C | Comma |
| / | %2F | Forward slash |
| : | %3A | Colon |
| ; | %3B | Semicolon |
| = | %3D | Equals sign |
| ? | %3F | Question mark |
| @ | %40 | At sign |
| [ | %5B | Open bracket |
| ] | %5D | Close bracket |
Unicode characters are encoded as their UTF-8 byte sequences:
- € (Euro) → %E2%82%AC
- 🌍 (Earth) → %F0%9F%8C%8D
URL Encoding vs Base64
URL encoding and Base64 are different encoding schemes:
URL Encoding (Percent-Encoding)
- Purpose: Make characters safe for URLs
- Output: Same characters with % escapes
- Size: Increases by ~3x for encoded chars only
- Use case: Query strings, form data
Base64 Encoding
- Purpose: Convert binary to text
- Output: A-Z, a-z, 0-9, +, /, =
- Size: Always increases by ~33%
- Use case: Embedding binary data in text
When to use which:
- URL encode: When building URLs with special characters
- Base64: When embedding binary data (images, files) in text
Combining both:
Sometimes you need both! For example, embedding Base64 data in a URL:
const base64Data = "SGVsbG8gV29ybGQh";const url = `https://api.com/data?b64=${encodeURIComponent(base64Data)}`;
Common Mistakes to Avoid
1. Double encoding
1// ❌ Wrong: encoding an already encoded string2const encoded = encodeURIComponent("%20");3// Results in: "%2520"45// ✅ Correct: only encode once6const text = " ";7const encoded = encodeURIComponent(text);8// Results in: "%20"
2. Using encodeURI for parameter values
1// ❌ Wrong: encodeURI doesn't encode &, =2const param = "a=1&b=2";3const bad = `url?data=${encodeURI(param)}`;4// "url?data=a=1&b=2" (breaks the URL!)56// ✅ Correct: use encodeURIComponent7const good = `url?data=${encodeURIComponent(param)}`;8// "url?data=a%3D1%26b%3D2"
3. Not encoding user input
1// ❌ Dangerous: XSS and URL injection risk2const search = userInput;3const url = `/search?q=${search}`;45// ✅ Safe: always encode untrusted input6const url = `/search?q=${encodeURIComponent(search)}`;
4. Forgetting + vs %20 for spaces
- Spaces in query strings can be either + or %20
- URLSearchParams uses +
- encodeURIComponent uses %20
- Both are valid; be consistent