URL Encoder & Decoder: The Complete Developer Guide
If you've ever seen %20 in a URL instead of a space, or wondered why & becomes %26, or why your perfectly crafted link breaks when it contains an emoji — you need to understand URL encoding. This guide covers everything you need to encode and decode URLs correctly, avoid the traps that break links in production, and understand the difference between encodeURI and encodeURIComponent.
Try the free URL Encoder & Decoder tool — it handles auto-detect, batch mode, and double-encoding detection.
What Is URL Encoding?
URL encoding, also called percent-encoding or URI encoding, is a way to represent characters inside a URL that would otherwise be illegal, ambiguous, or dangerous. URLs are defined by RFC 3986 and can only contain a very limited set of ASCII characters:
- Uppercase letters:
A–Z - Lowercase letters:
a–z - Digits:
0–9 - Unreserved characters:
- _ . ~ - Reserved gen-delim:
: / ? # [ ] @ - Reserved sub-delim:
! $ & ' ( ) * + , ; =
Every character outside this set must be percent-encoded: converted to a % followed by two hexadecimal digits representing the character's byte value in UTF-8. A space (U+0020) becomes %20. The question mark (U+003F) becomes %3F. An emoji like 😅 (U+1F601) becomes %F0%9F%98%81 — four encoded bytes because UTF-8 uses multiple bytes for characters outside ASCII.
URLs with unencoded special characters break in unexpected ways. Some servers silently truncate at the first space. Others interpret & as a query parameter delimiter and split your value. Browsers may re-encode your URL on the fly, making it look encoded when it isn't. Always encode before transmitting a URL.
The Two Functions: encodeURI vs encodeURIComponent
This is the most common source of confusion in URL encoding. JavaScript provides two built-in functions that do different things:
encodeURIComponent() — For Individual Values
Use this when encoding a single query parameter value or path segment. It encodes everything except the ASCII alphanumeric characters and - _ . ~ ! ' ( ) * ; : @ & = + $ , / ? #. Specifically, it will encode:
encodeURIComponent("hello world")
// → "hello%20world"
encodeURIComponent("café & pastries")
// → "caf%C3%A9%20%26%20pastries"
encodeURIComponent("https://example.com")
// → "https%3A%2F%2Fexample.com"
// ⚠️ This destroys the URL structure!
encodeURI() — For Complete URLs
Use this when encoding a complete URL that you want to remain a valid URL. It preserves the characters that have structural meaning in URLs:
encodeURI("https://example.com/search?q=hello world")
// → "https://example.com/search?q=hello%20world"
// ✅ The : // ? = and space in "q=" are preserved
encodeURI("https://example.com/?q=café")
// → "https://example.com/?q=caf%C3%A9"
// ✅ The ? and = are preserved
| Character | encodeURIComponent() | encodeURI() | Reasoning |
|---|---|---|---|
(space) |
%20 |
%20 |
Not allowed in any URL component |
/ |
%2F |
/ |
Path separator — must be preserved in URLs |
? |
%3F |
? |
Query string delimiter — must be preserved |
& |
%26 |
& |
Query parameter separator — must be preserved |
# |
%23 |
# |
Fragment identifier delimiter — must be preserved |
= |
%3D |
= |
Key/value separator in query strings — preserved in encodeURI |
+ |
%2B |
+ |
+ is valid in encodeURI; encoded in encodeURIComponent |
The golden rule: encode your query parameter values individually with encodeURIComponent(), then assemble the full URL. Never pass a complete URL to encodeURIComponent() — you'll destroy its structure.
Common URL Encoded Characters
Here's a quick reference for the most common encoded characters you'll encounter:
| Character | Encoded | Common Scenario |
|---|---|---|
(space) | %20 | Any space in a query value or path |
! | %21 | Exclamation marks in query strings |
" | %22 | Quotes in URL parameters |
# | %23 | Hashes in values (not as fragment) |
$ | %24 | Dollar signs in amounts/prices |
% | %25 | Percent signs — the escape character itself |
& | %26 | Ampersands in parameter values |
' | %27 | Apostrophes in names and quotes |
( ) | %28 %29 | Parentheses in search queries |
+ | %2B | Plus signs in phone numbers |
/ | %2F | Slashes in encoded path segments |
: | %3A | Colons in timestamps like "10:30" |
< > | %3C %3E | Angle brackets in text content |
\ | %5C | Backslashes in Windows paths |
~ | %7E | Tildes in some encoded contexts |
é | %C3%A9 | Accented Latin letters |
中 | %E4%B8%AD | Multibyte characters (Chinese, emoji, etc.) |
Double Encoding: The Silent URL Killer
Double-encoding is one of the most insidious URL bugs in production. It happens when software encodes data that was already percent-encoded. The result: %20 (a space) becomes %2520 (% encoded to %25 + 20).
Original: "Hello World" (with a space)
First encode: "Hello%20World"
Second encode: "Hello%2520World" ← breaks here
This commonly happens through:
- Multiple proxies — each proxy independently encodes the URL, compounding the issue
- Double-processing — a web framework encodes URLs on both input and output
- Redirect loops — a redirect handler re-encodes an already-encoded URL
- Database storage — values are stored encoded and then encoded again on retrieval
The most dangerous aspect of double-encoding is that it's often silent — the URL appears to work in some contexts and fail in others, making it extremely hard to debug.
Double-encoding has been exploited in injection attacks, particularly HTTP Parameter Pollution (HPP) attacks. Attackers deliberately send double-encoded values that get decoded once by a WAF and once by the application backend, bypassing security filters. Always validate and sanitize URL parameters at the application boundary, not just encode them.
How to Decode URLs in Different Languages
JavaScript
// Decode a single value
decodeURIComponent("caf%C3%A9%20%26%20pastries")
// → "café & pastries"
// Decode a full URL (if you must)
decodeURI("https://example.com/search?q=hello%20world")
// → "https://example.com/search?q=hello world"
// Safe decode with error handling
function safeDecode(str) {
try { return decodeURIComponent(str); }
catch (e) { return str; }
}
Python
import urllib.parse
# Decode query parameter values
urllib.parse.unquote("caf%C3%A9%20%26%20pastries")
# → "café & pastries"
# Decode full URL
urllib.parse.unquote("https://example.com/search?q=hello%20world")
# → "https://example.com/search?q=hello world"
# For Python 3.7+
urllib.parse.parse_qs("q=hello%20world")['q']
# → ['hello world']
bash / Command Line
# Using Python
python3 -c "import urllib.parse; print(urllib.parse.unquote('Hello%20World'))"
# → Hello World
# Using printf (bash built-in)
printf '%s\n' "$(printf '%s' 'Hello%%20World' | sed 's/%\(..\)/\\x\1/g')"
# Requires printf to interpret hex sequences
The + vs %20: Why Form Data Uses Different Encoding
There's a legacy inconsistency in how HTML forms encode spaces. The application/x-www-form-urlencoded format (used by traditional HTML form submissions) converts spaces to + instead of %20. URL percent-encoding uses %20 for spaces.
application/x-www-form-urlencoded (HTML forms):
"hello world" → "q=hello+world"
text/uri-list (URLs and JSON APIs):
"hello world" → "q=hello%20world"
This matters when parsing query strings — the same data encoded two different ways needs different parsing logic. Most modern APIs use JSON or proper percent-encoding, but you'll still encounter the + format in legacy systems.
Encoding URLs in Email and SMS
One of the most common real-world URL encoding problems is email and SMS links containing special characters. Email clients, SMS apps, and link shorteners may handle percent-encoded URLs differently:
- Email clients may strip or misinterpret
+as space in some contexts - SMS apps on Android and iOS may auto-convert certain characters
- Some link shorteners re-encode already-encoded URLs, causing double-encoding
- QR codes that encode URLs must use UTF-8 — always percent-encode non-ASCII characters
Best practice for marketing URLs: always encode the full URL before embedding it in email templates, SMS messages, or QR codes. Test the URL by clicking it from within the target application — not just by pasting it in a browser.
How the SnapUtils URL Encoder & Decoder Helps
The URL Encoder & Decoder tool at SnapUtils handles the real-world scenarios that most online encoders miss:
- Auto-detect mode — paste any URL and the tool instantly detects whether it's encoded or plain text. No guessing which direction to choose.
- encodeURI vs encodeURIComponent toggle — switch between full URL encoding and component encoding without re-copying your text
- Batch mode — encode or decode multiple URLs at once, one per line. Useful for cleaning up lists of URLs from spreadsheets or log files
- Double-encoding detection — if the tool spots
%2520patterns, it warns you before you accidentally decode into garbled text - Character reference table — 30+ common encoded characters with descriptions, plus an "Insert" button to add them to your input
Try the URL Encoder & Decoder
Instantly encode and decode URLs. Auto-detect, batch mode, and double-encoding detection.
Open Tool →Quick Reference: Encoding Checklist
- ☐ Encode each query parameter value individually with
encodeURIComponent()before assembling the URL - ☐ Never pass a complete URL to
encodeURIComponent()— it will destroy the structure - ☐ Use
encodeURI()only for complete URLs where you want to preserve URL structure - ☐ Check for double-encoding if your decoded URLs still contain
%XXsequences - ☐ Test URLs containing non-ASCII characters (emoji, accents, CJK) from within the target context (email, SMS, QR code)
- ☐ Log raw URL values at your API boundary to make double-encoding bugs visible in traces
- ☐ Don't use
+for spaces in API URLs — use%20