1. Introduction to URL Encoding in JavaScript
JavaScript provides two essential functions for URL encoding: encodeURI() and encodeURIComponent(). While they sound similar, they serve fundamentally different purposes and encode different character sets.
๐ก Pro Tip
Key Takeaway
encodeURI() preserves URL structure (keeps ://?&=# intact). encodeURIComponent() encodes EVERYTHING - use for query parameter values.
2. encodeURI() - Complete Deep Dive
encodeURI() is designed to encode a complete, valid URL. It preserves characters that have special meaning in URL syntax.
// Syntax
encodeURI(uri: string): string
// What it preserves (DOES NOT encode)
A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #
// What it encodes
space โ %20, " โ %22, { โ %7B, } โ %7D, | โ %7C, \ โ %5C, ^ โ %5E, % โ %25, [ โ %5B, ] โ %5D
Examples:
encodeURI("https://example.com/path with spaces")
โ "https://example.com/path%20with%20spaces"
encodeURI("https://example.com/search?q=hello&lang=en")
โ "https://example.com/search?q=hello&lang=en" (unchanged)
encodeURI("https://example.com/#fragment with space")
โ "https://example.com/#fragment%20with%20space"3. encodeURIComponent() - Complete Deep Dive
encodeURIComponent() encodes ALL special characters, including those that have meaning in URL syntax. This is ideal for encoding user input that will become part of a query parameter or path segment.
// Syntax
encodeURIComponent(str: string): string
// What it DOES NOT encode (only these 71 chars are safe)
A-Z a-z 0-9 - _ . ! ~ * ' ( )
// What it DOES encode (EVERYTHING else)
: โ %3A, / โ %2F, ? โ %3F, # โ %23, [ โ %5B, ] โ %5D, @ โ %40 ! โ %21, $ โ %24, & โ %26, ' โ %27, ( โ %28, ) โ %29, * โ %2A + โ %2B, , โ %2C, ; โ %3B, = โ %3D, space โ %20, " โ %22, % โ %25
Examples:
encodeURIComponent("hello world")
โ "hello%20world"
encodeURIComponent("hello&world=test")
โ "hello%26world%3Dtest"
encodeURIComponent("https://example.com")
โ "https%3A%2F%2Fexample.com" (URL becomes unusable!)
encodeURIComponent("user@example.com")
โ "user%40example.com"4. Complete Comparison Matrix
| Character | ASCII | encodeURI() | encodeURIComponent() | Safe in URL? |
|---|---|---|---|---|
| : | 58 | : (kept) | %3A | Protocol |
| / | 47 | / (kept) | %2F | Path |
| ? | 63 | ? (kept) | %3F | Query start |
| # | 35 | # (kept) | %23 | Fragment |
| & | 38 | & (kept) | %26 | Param separator |
| = | 61 | = (kept) | %3D | Key-value |
| @ | 64 | @ (kept) | %40 | Userinfo |
| space | 32 | %20 | %20 | Must encode |
| + | 43 | + (kept) | %2B | Reserved |
| % | 37 | %25 | %25 | Encoder |
| - | 45 | - (kept) | - (kept) | Unreserved |
| _ | 95 | _ (kept) | _ (kept) | Unreserved |
| ! | 33 | ! (kept) | ! (kept) | Unreserved |
| ~ | 126 | ~ (kept) | ~ (kept) | Unreserved |
5. 10+ Real-World Examples
Example 1: Building a search URL with user input
const searchQuery = "javascript tutorial & examples";
const encodedQuery = encodeURIComponent(searchQuery);
const url = `https://google.com/search?q=${encodedQuery}`;
// Result: https://google.com/search?q=javascript%20tutorial%20%26%20examplesExample 2: API call with nested parameters
const params = { filter: "category=books&sort=desc", page: 1 };
const queryString = Object.keys(params)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join('&');
// Result: filter=category%3Dbooks%26sort%3Ddesc&page=1Example 3: Email in URL (mailto:)
const email = "user+filter@example.com";
const subject = "Meeting tomorrow & agenda";
const mailtoUrl = `mailto:${encodeURIComponent(email)}?subject=${encodeURIComponent(subject)}`;
// Result: mailto:user%2Bfilter%40example.com?subject=Meeting%20tomorrow%20%26%20agendaExample 4: Path segment with special chars
const username = "john.doe+admin";
const encodedUsername = encodeURIComponent(username);
const profileUrl = `https://api.com/users/${encodedUsername}/profile`;
// Result: https://api.com/users/john.doe%2Badmin/profileExample 5: Fragment identifier with spaces
const section = "chapter 1: introduction"; const fragment = encodeURIComponent(section); // Result: #chapter%201%3A%20introduction
Example 6: Handling redirect URLs
const returnUrl = "https://example.com/dashboard?tab=profile&lang=en";
const encodedReturnUrl = encodeURIComponent(returnUrl);
const loginUrl = `https://auth.com/login?redirect=${encodedReturnUrl}`;
// Result: https://auth.com/login?redirect=https%3A%2F%2Fexample.com%2Fdashboard%3Ftab%3Dprofile%26lang%3DenExample 7: Form data with spaces and special chars
const formData = { name: "John & Jane Doe", comment: "Check this out: https://example.com", rating: "5/5" };
const encoded = Object.entries(formData)
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&');
// Result: name=John%20%26%20Jane%20Doe&comment=Check%20this%20out%3A%20https%3A%2F%2Fexample.com&rating=5%2F56. When to Use Which? Decision Framework
Use encodeURI() when:
- You have a complete, valid URL
- You want to encode unsafe characters but preserve URL structure
- You are encoding the entire URL (scheme + domain + path + query)
- encodeURI("https://example.com/path with spaces")
Use encodeURIComponent() when:
- You are building query string parameter values
- You are encoding path segments with special chars
- You are encoding user input that will be part of a URL
- encodeURIComponent("user input & special=chars")
Decision Flowchart (Mental Model)
Is this a complete URL (with protocol and domain)?
โโ YES โ Use encodeURI() for the whole string
โ Exception: If URL contains user-controlled parts, encode them with encodeURIComponent() first
โ
โโ NO โ Is this data going into a query parameter?
โโ YES โ Use encodeURIComponent()
โโ Is this a path segment? โ Use encodeURIComponent()
โโ Is this a fragment (#section)? โ Use encodeURIComponent()7. Security Considerations & Attack Vectors
โ ๏ธ Warning
Common Security Vulnerabilities
Double Encoding Attack:
// Attacker input: %25%33%63 (which decodes to %3c, then to <)
const decodedOnce = decodeURIComponent("%25%33%63"); // "%3c" (still encoded!)
const decodedTwice = decodeURIComponent(decodedOnce); // "<" (XSS payload!)Parameter Pollution via Encoded Delimiters:
// Attacker input: "value&admin=true" // Without encodeURIComponent(): URL becomes ?q=value&admin=true โ admin parameter injected! // With encodeURIComponent(): "value%26admin%3Dtrue" โ safe
โ Good to Know
Security Best Practices
- Always use encodeURIComponent() for user input in query parameters
- Never decode user input before validation (can lead to double-decode attacks)
- Use allow-lists for allowed characters when possible
- Validate URLs after decoding, but before using them
- Consider using URL constructor instead of string concatenation
8. Performance Analysis & Benchmarks
| Operation | Short String (10 chars) | Medium String (100 chars) | Long String (1000 chars) |
|---|---|---|---|
| encodeURI() | ~0.001ms | ~0.005ms | ~0.05ms |
| encodeURIComponent() | ~0.001ms | ~0.005ms | ~0.05ms |
| Manual replace() | ~0.005ms | ~0.03ms | ~0.3ms |
Note: Native functions are highly optimized. Use them instead of custom implementations.
9. 7 Common Pitfalls & Solutions
Pitfall 1: Using encodeURI() for query parameters
โ encodeURI("hello&world") โ "hello&world" (unchanged, breaks URL!)
โ
encodeURIComponent("hello&world") โ "hello%26world"Pitfall 2: Double encoding
โ encodeURIComponent(encodeURIComponent("hello")) โ "hello%2520"
โ
encodeURIComponent("hello") โ "hello%20"
โ
Only encode once at the boundaryPitfall 3: Forgetting to decode when displaying
โ displayText = encodedValue // Shows "hello%20world" to user โ displayText = decodeURIComponent(encodedValue) // Shows "hello world"
Pitfall 4: Encoding already valid URLs completely
โ const url = encodeURIComponent("https://example.com") โ "https%3A%2F%2Fexample.com"
โ
const url = "https://example.com/" + encodeURIComponent(path)Pitfall 5: Mixing + and %20 for spaces
โ "hello+world" + "&name=" + encodeURIComponent("Jane Doe") โ inconsistent
โ
Always use %20 via encodeURIComponent() for consistencyPitfall 6: Not handling null/undefined values
โ encodeURIComponent(undefined) โ "undefined" (string!) โ if (value === null || value === undefined) value = ""
Pitfall 7: Assuming all special chars are encoded the same across languages
// PHP: urlencode() uses + for spaces, rawurlencode() uses %20 // JS: encodeURIComponent() uses %20 // Be consistent across backend/frontend!
10. Decoding: decodeURI() vs decodeURIComponent()
decodeURI()
decodeURI("https%3A%2F%2Fexample.com")
โ "https%3A%2F%2Fexample.com" (doesn't decode %3A or %2F)
decodeURI("https://example.com/%20")
โ "https://example.com/ "decodeURIComponent()
decodeURIComponent("https%3A%2F%2Fexample.com")
โ "https://example.com" (decodes everything)
decodeURIComponent("%20%26%3D")
โ " &="11. Advanced Patterns & Utilities
// Safe URL builder utility
function buildUrl(baseUrl, pathSegments, queryParams) {
// Encode path segments
const encodedPath = pathSegments
.map(segment => encodeURIComponent(segment))
.join('/');
// Build query string
const queryString = queryParams
? '?' + Object.entries(queryParams)
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&')
: '';
return `${baseUrl}/${encodedPath}${queryString}`;
}
// Usage
buildUrl('https://api.com', ['users', 'john doe'], { filter: 'books & more', page: 1 });
// โ https://api.com/users/john%20doe?filter=books%20%26%20more&page=112. Summary & Cheatsheet
Quick Reference Card
Use encodeURI() for:
- Complete URLs
- Preserving URL structure
- Whole URL encoding
Use encodeURIComponent() for:
- Query parameter values
- Path segments
- Form data encoding
- Fragment identifiers
Remember:
encodeURIComponent() encodes MORE characters than encodeURI()
Both encode spaces as %20 (not +)
Always decode with the matching function
Never encode an already encoded string
Ready to encode like a pro?
Use our interactive URL encoder/decoder with real-time feedback
