URL Encode & Decode — Percent Encoding Explained
Last updated:
URL encoding (percent encoding, RFC 3986) replaces every character outside the 66 unreserved ASCII characters with a % sign followed by 2 hex digits — a space becomes %20, & becomes %26, and a 2-byte UTF-8 character like é produces 2 sequences (%C3%A9). JavaScript exposes 2 encoding functions with different scope: encodeURIComponent() encodes all characters except the 66 unreserved ones, while encodeURI() also preserves 18 structural characters like / ? # & = :; HTML forms use application/x-www-form-urlencoded and encode spaces as + instead of %20. This guide covers encodeURI vs encodeURIComponent,URLSearchParams for query strings, Python's urllib.parse functions (quote, quote_plus, urlencode), the %20 vs + space encoding difference, and 3 common mistakes including double-encoding.
URL encode or decode online
Paste any string to percent-encode it for URL use, or decode a URL-encoded string back to plain text — instantly in your browser.
Open URL Encoder / DecoderWhat is URL encoding?
URLs can only contain a limited set of ASCII characters. Any character outside that set — spaces, accented letters, symbols, non-Latin scripts — must be percent-encoded before being placed in a URL. Each byte of the character is represented as %XX, where XX is the hexadecimal byte value.
Space → %20
/ → %2F
? → %3F
# → %23
& → %26
= → %3D
+ → %2B
@ → %40
é → %C3%A9 (UTF-8: two bytes)URL encoding in JavaScript
JavaScript provides two pairs of functions for URL encoding, each with different scope:
// encodeURIComponent — encode a single value (recommended for query params)
encodeURIComponent('hello world') // "hello%20world"
encodeURIComponent('a=1&b=2') // "a%3D1%26b%3D2"
encodeURIComponent('https://x.com') // "https%3A%2F%2Fx.com"
// decodeURIComponent — reverse of the above
decodeURIComponent('hello%20world') // "hello world"
decodeURIComponent('%C3%A9l%C3%A8ve') // "élève"
// encodeURI — encode a full URL (preserves :, /, ?, #, &, =)
encodeURI('https://example.com/path with spaces?q=hello world')
// "https://example.com/path%20with%20spaces?q=hello%20world"
// decodeURI — reverse of encodeURI
decodeURI('https://example.com/path%20with%20spaces')
// "https://example.com/path with spaces"Use encodeURIComponent for individual query parameter values. Use encodeURI only for complete URLs where you want to preserve the URL structure characters.
Encode query parameters correctly in JavaScript
// Wrong — encodes the = and & signs, breaking the URL structure
const bad = encodeURIComponent('https://api.example.com/search?q=hello world&lang=en')
// Correct — encode only the values
const q = encodeURIComponent('hello world')
const lang = encodeURIComponent('en')
const url = `https://api.example.com/search?q=${q}&lang=${lang}`
// "https://api.example.com/search?q=hello%20world&lang=en"
// Even better — use URLSearchParams
const params = new URLSearchParams({ q: 'hello world', lang: 'en' })
const url2 = `https://api.example.com/search?${params}`
// "https://api.example.com/search?q=hello+world&lang=en"
// Note: URLSearchParams uses + for spaces, not %20URL encoding in Python
from urllib.parse import quote, unquote, urlencode, quote_plus, unquote_plus
# Encode a single value (safe='/' keeps slashes unencoded)
quote('hello world') # 'hello%20world'
quote('hello world', safe='') # 'hello%20world'
quote('/path/to/file') # '/path/to/file' (/ preserved by default)
quote('/path/to/file', safe='') # '%2Fpath%2Fto%2Ffile'
# Decode
unquote('hello%20world') # 'hello world'
unquote('%C3%A9l%C3%A8ve') # 'élève'
# Encode query parameters (uses + for spaces, like HTML forms)
quote_plus('hello world') # 'hello+world'
unquote_plus('hello+world') # 'hello world'
# Encode a full query string from a dict
params = {'q': 'hello world', 'lang': 'en', 'page': 1}
urlencode(params) # 'q=hello+world&lang=en&page=1'%20 vs + for spaces
Spaces can be encoded as either %20 or +, depending on context:
| Context | Space encoding | Function |
|---|---|---|
| URL path segments | %20 | encodeURIComponent |
HTML form submissions (application/x-www-form-urlencoded) | + | URLSearchParams |
| Query strings (general) | Either (prefer %20) | — |
Modern APIs and browsers accept both, but %20 is more universally safe.
Characters that do NOT need encoding
These characters are safe in URLs and are left unencoded by encodeURIComponent:
A–Z a–z 0–9 - _ . ! ~ * ' ( )All other characters — including /, ?, #,&, =, +, and any non-ASCII characters — are encoded when passed through encodeURIComponent.
Common URL encoding mistakes
- Double-encoding — encoding an already-encoded string produces
%2520instead of%20. Always decode before re-encoding. - Using
encodeURIon values — it preserves=and&, so query parameter values with those characters won't be properly escaped. - Not encoding Unicode — characters outside ASCII must be UTF-8 encoded first, then percent-encoded. Modern functions handle this automatically.
Decode a URL online
Paste any percent-encoded URL or string into the URL Encode / Decode tool to instantly encode or decode it. For Base64-encoded strings (common in JWTs and data URIs), use the Base64 tool instead.
Frequently asked questions
Which characters must be percent-encoded in URLs?
Only unreserved characters can appear unencoded: A–Z, a–z, 0–9, hyphen, underscore, period, and tilde. Everything else — spaces, /, ?, #, &, =, @, non-ASCII characters, and control characters — must be percent-encoded as %XX where XX is the hexadecimal byte value.
What is the difference between encodeURI and encodeURIComponent in JavaScript?
encodeURIComponent encodes all characters except unreserved ones — including /, ?, #, &, and =. Use it for individual query parameter values. encodeURI preserves URL structure characters like / ? # & and :. Use it only for full URLs. Never use encodeURI on query parameter values — it leaves = and & unencoded.
How do I URL-encode in Python?
Use urllib.parse: quote() for path segments (preserves / by default, encodes spaces as %20), quote_plus() for query values (encodes spaces as +), and urlencode() for full query strings from a dict. Decode with unquote() or unquote_plus() for +-encoded strings.
What is %20 in a URL?
%20 is the percent-encoded space character. Space is ASCII decimal 32, hexadecimal 20. URLs cannot contain literal spaces, so they must be encoded as %20 in path segments or as + in query strings (HTML form encoding). Both represent the same space character.
Can spaces be in URLs?
No. RFC 3986 does not allow literal spaces in URLs. Browsers auto-encode spaces in the address bar, but in code you must encode explicitly using encodeURIComponent in JavaScript or quote() in Python. Do not rely on client auto-encoding as behavior varies between environments.
What does + mean in a URL query string?
In a query string (after ?), + represents a space — an HTML form encoding convention. In the URL path, + is a literal plus sign. %20 works for spaces in both paths and query strings, making it the safer universal choice. Decode + as space using decodeURIComponent on query string values.
Recommended reading
- Designing Data-Intensive Applications (2nd Edition) — Martin Kleppmann & Chris RiccominiThe modern classic on data systems — encoding formats, schemas, replication, and stream processing.
- JavaScript: The Definitive Guide (7th Edition) — David FlanaganThe complete reference for the language JSON came from — serialization, async, and the full standard library.
As an Amazon Associate, Jsonic earns from qualifying purchases.