URL encoding (also called percent encoding) converts special characters into a format that can be safely transmitted in a URL. Every developer encounters URL encoding issues at some point — broken links, garbled parameters, or API errors caused by unencoded characters. This complete URL encoding reference gives you the definitive table of all special characters and their encoded forms, plus practical examples in every major programming language.
Encode or decode any URL instantly with our URL Encoder/Decoder tool →
What Is URL Encoding (Percent Encoding)?
URL encoding replaces unsafe or reserved characters with a % sign followed by two hexadecimal digits representing the character's ASCII/UTF-8 byte value. For example, a space becomes %20, and an ampersand becomes %26.
This mechanism is defined in RFC 3986 (Uniform Resource Identifier: Generic Syntax). URLs can only contain a limited set of characters from the US-ASCII character set. Any character outside this set — or any reserved character used outside its special meaning — must be percent-encoded.
The general format is: %XX where XX is the hexadecimal value of the byte. For multi-byte UTF-8 characters (like Chinese or emoji), each byte is encoded separately. For example, the Chinese character "中" (U+4E2D) encodes to %E4%B8%AD (three bytes in UTF-8).
// URL encoding example
Original: https://example.com/search?q=hello world&lang=en
Encoded: https://example.com/search?q=hello%20world&lang=en
// The space in "hello world" becomes %20
// The & and = remain unencoded (they are structural)Complete URL Encoding Reference Table
Below is a comprehensive table of all commonly encountered special characters and their percent-encoded forms. Bookmark this page for quick reference.
| Character | Encoded Form | ASCII Code | Description |
|---|---|---|---|
(space) | %20 | 32 | Space (also + in form data) |
! | %21 | 33 | Exclamation mark |
" | %22 | 34 | Double quote |
# | %23 | 35 | Hash / Fragment identifier |
$ | %24 | 36 | Dollar sign |
% | %25 | 37 | Percent sign (the escape character itself) |
& | %26 | 38 | Ampersand / Parameter separator |
' | %27 | 39 | Single quote (apostrophe) |
( | %28 | 40 | Left parenthesis |
) | %29 | 41 | Right parenthesis |
* | %2A | 42 | Asterisk |
+ | %2B | 43 | Plus sign (space in form data) |
, | %2C | 44 | Comma |
/ | %2F | 47 | Forward slash / Path separator |
: | %3A | 58 | Colon (scheme separator) |
; | %3B | 59 | Semicolon |
< | %3C | 60 | Less than |
= | %3D | 61 | Equals sign (key-value separator) |
> | %3E | 62 | Greater than |
? | %3F | 63 | Question mark (query string start) |
@ | %40 | 64 | At sign (email / userinfo separator) |
[ | %5B | 91 | Left square bracket |
\ | %5C | 92 | Backslash |
] | %5D | 93 | Right square bracket |
^ | %5E | 94 | Caret |
` | %60 | 96 | Backtick (grave accent) |
{ | %7B | 123 | Left curly brace |
| | %7C | 124 | Pipe (vertical bar) |
} | %7D | 125 | Right curly brace |
~ | %7E | 126 | Tilde (unreserved in RFC 3986) |
\n | %0A | 10 | Line feed (newline) |
\r | %0D | 13 | Carriage return |
\t | %09 | 9 | Horizontal tab |
Reserved vs Unreserved Characters (RFC 3986)
RFC 3986 defines two categories of characters that determine when encoding is necessary:
Reserved Characters
These characters have special meaning in URLs. If you want to use them literally (not for their special purpose), you must percent-encode them.
: / ? # [ ] @ ! $ & ' ( ) * + , ; =
// Reserved characters in RFC 3986
gen-delims = : / ? # [ ] @
sub-delims = ! $ & ' ( ) * + , ; =
// Example: & is reserved (parameter separator)
// To use & literally in a value, encode it:
?search=Tom%26Jerry // searching for "Tom&Jerry"
?search=Tom&Jerry // WRONG: "Jerry" becomes a separate paramUnreserved Characters
These characters can be used in a URL without encoding. They have no special meaning:
Letters: A-Z, a-z Digits: 0-9 Special: - _ . ~
// Unreserved characters (RFC 3986) — never need encoding
ALPHA = A-Z / a-z
DIGIT = 0-9
other = - . _ ~
// These are always safe in any part of a URL:
https://example.com/my-file_name.v2~backupEverything else — including spaces, non-ASCII characters, and control characters — must always be percent-encoded.
encodeURI vs encodeURIComponent in JavaScript
JavaScript provides two built-in functions for URL encoding, and using the wrong one is one of the most common mistakes:
encodeURI()
Encodes a complete URI. It does NOT encode characters that have special meaning in a URL: : / ? # [ ] @ ! $ & ' ( ) * + , ; =
// encodeURI() — for complete URLs
const url = 'https://example.com/path name/file?q=hello world';
encodeURI(url);
// → "https://example.com/path%20name/file?q=hello%20world"
// Note: :, /, ?, = are NOT encoded (URL structure preserved)encodeURIComponent()
Encodes a URI component (such as a query parameter value). It DOES encode reserved characters like & = + / — which is exactly what you want for parameter values.
// encodeURIComponent() — for parameter values
const query = 'price=100¤cy=USD';
encodeURIComponent(query);
// → "price%3D100%26currency%3DUSD"
// Note: = and & ARE encoded (they're data, not structure)
// Correct usage: build URL piece by piece
const base = 'https://api.example.com/search';
const param = 'Tom & Jerry: The Movie';
const fullUrl = base + '?q=' + encodeURIComponent(param);
// → "https://api.example.com/search?q=Tom%20%26%20Jerry%3A%20The%20Movie"Rule of thumb: Use encodeURIComponent() for query parameter values and path segments. Use encodeURI() only when encoding an entire URL where you want to preserve the structure.
// Side-by-side comparison
const text = 'hello world & goodbye=fun';
encodeURI(text);
// → "hello%20world%20&%20goodbye=fun"
// & and = are NOT encoded
encodeURIComponent(text);
// → "hello%20world%20%26%20goodbye%3Dfun"
// & and = ARE encoded
// decodeURI() and decodeURIComponent() reverse the process
decodeURIComponent('%E4%B8%AD%E6%96%87'); // → "中文"URL Encoding in Different Programming Languages
Python
# Python 3 — urllib.parse
from urllib.parse import quote, quote_plus, unquote, urlencode
# Encode a path segment (spaces → %20)
quote('hello world/file name')
# → 'hello%20world/file%20name' (/ is safe by default)
# Encode a path segment including /
quote('hello world/file name', safe='')
# → 'hello%20world%2Ffile%20name'
# Encode a query parameter value (spaces → +)
quote_plus('hello world&foo=bar')
# → 'hello+world%26foo%3Dbar'
# Build query string from dict
urlencode({'q': 'Tom & Jerry', 'page': '1'})
# → 'q=Tom+%26+Jerry&page=1'
# Decode
unquote('%E4%B8%AD%E6%96%87') # → '中文'Java
// Java — URLEncoder / URI
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
// Encode a query parameter value (spaces → +)
String encoded = URLEncoder.encode(
"hello world&foo=bar", StandardCharsets.UTF_8
);
// → "hello+world%26foo%3Dbar"
// Decode
String decoded = URLDecoder.decode(
"hello+world%26foo%3Dbar", StandardCharsets.UTF_8
);
// → "hello world&foo=bar"
// For path segments, use URI class
import java.net.URI;
URI uri = new URI("https", "example.com", "/path with spaces", "q=hello world", null);
// → https://example.com/path%20with%20spaces?q=hello%20worldGo
// Go — net/url package
package main
import (
"fmt"
"net/url"
)
func main() {
// Encode a query parameter value
encoded := url.QueryEscape("hello world&foo=bar")
// → "hello+world%26foo%3Dbar"
// Encode a path segment
pathEncoded := url.PathEscape("hello world/file")
// → "hello%20world%2Ffile"
// Build a complete URL safely
u := &url.URL{
Scheme: "https",
Host: "example.com",
Path: "/search",
}
q := u.Query()
q.Set("q", "Tom & Jerry")
q.Set("lang", "en")
u.RawQuery = q.Encode()
fmt.Println(u.String())
// → "https://example.com/search?lang=en&q=Tom+%26+Jerry"
}PHP
<?php
// PHP — urlencode / rawurlencode
// Query parameter encoding (spaces → +)
echo urlencode('hello world&foo=bar');
// → "hello+world%26foo%3Dbar"
// Path segment encoding (spaces → %20, RFC 3986)
echo rawurlencode('hello world&foo=bar');
// → "hello%20world%26foo%3Dbar"
// Build query string from array
echo http_build_query([
'q' => 'Tom & Jerry',
'page' => 1
]);
// → "q=Tom+%26+Jerry&page=1"
// Decode
echo urldecode('hello+world%26foo%3Dbar');
// → "hello world&foo=bar"
echo rawurldecode('hello%20world%26foo%3Dbar');
// → "hello world&foo=bar"
?>C#
// C# — Uri.EscapeDataString / HttpUtility
using System;
using System.Web;
// Encode a URI component (RFC 3986)
string encoded = Uri.EscapeDataString("hello world&foo=bar");
// → "hello%20world%26foo%3Dbar"
// Encode for query string (spaces → +)
string queryEncoded = HttpUtility.UrlEncode("hello world&foo=bar");
// → "hello+world%26foo%3Dbar"
// Decode
string decoded = Uri.UnescapeDataString("hello%20world%26foo%3Dbar");
// → "hello world&foo=bar"
// Build query string
var query = HttpUtility.ParseQueryString(string.Empty);
query["q"] = "Tom & Jerry";
query["page"] = "1";
string queryString = query.ToString();
// → "q=Tom+%26+Jerry&page=1"Ruby
# Ruby — URI / CGI
require 'uri'
require 'cgi'
# Encode a component (spaces → %20)
URI.encode_www_form_component('hello world&foo=bar')
# → "hello+world%26foo%3Dbar"
# Encode for path (spaces → %20)
URI::DEFAULT_PARSER.escape('hello world')
# → "hello%20world"
# Build query string
URI.encode_www_form('q' => 'Tom & Jerry', 'page' => '1')
# → "q=Tom+%26+Jerry&page=1"
# Decode
CGI.unescape('hello%20world%26foo%3Dbar')
# → "hello world&foo=bar"Common URL Encoding Mistakes
1. Double Encoding
Double encoding happens when you encode an already-encoded string. For example, %20 becomes %2520 (the % gets encoded to %25). This is one of the most common and hardest-to-debug URL issues.
// Double encoding example
const value = 'hello world';
// First encoding (correct)
const encoded = encodeURIComponent(value);
// → "hello%20world"
// Accidentally encoding again (BUG!)
const doubleEncoded = encodeURIComponent(encoded);
// → "hello%2520world"
// %20 → %25 (the %) + 20 → %2520
// The server receives "hello%20world" instead of "hello world"
// Fix: only encode once, at the point where you build the URL2. Encoding the Entire URL
Never pass an entire URL to encodeURIComponent(). It will encode the ://, /, ?, and = characters, breaking the URL structure. Only encode individual parameter values.
// WRONG: encoding the entire URL
const url = 'https://example.com/api?q=hello world';
encodeURIComponent(url);
// → "https%3A%2F%2Fexample.com%2Fapi%3Fq%3Dhello%20world"
// Completely broken URL!
// CORRECT: only encode the parameter value
const base = 'https://example.com/api';
const query = 'hello world';
const correctUrl = base + '?q=' + encodeURIComponent(query);
// → "https://example.com/api?q=hello%20world"3. Forgetting + vs %20 for Spaces
In the application/x-www-form-urlencoded format (HTML forms), spaces are encoded as +. In standard percent encoding (RFC 3986), spaces are %20. Most server-side frameworks handle both, but APIs may be strict. When in doubt, use %20.
// + vs %20 for spaces
// Form data (application/x-www-form-urlencoded):
// "hello world" → "hello+world"
// RFC 3986 (URI standard):
// "hello world" → "hello%20world"
// In JavaScript:
encodeURIComponent('hello world'); // → "hello%20world"
// To get + for form data, replace after:
encodeURIComponent('hello world').replace(/%20/g, '+');
// → "hello+world"
// URLSearchParams automatically uses + for spaces:
new URLSearchParams({ q: 'hello world' }).toString();
// → "q=hello+world"4. Not Encoding Non-ASCII Characters
Characters like café, ü, or CJK characters must be UTF-8 encoded first, then each byte is percent-encoded. Forgetting this causes mojibake (garbled text) in URLs.
// Non-ASCII characters must be UTF-8 encoded first
encodeURIComponent('café');
// → "caf%C3%A9" (é = 2 UTF-8 bytes: C3 A9)
encodeURIComponent('中文');
// → "%E4%B8%AD%E6%96%87" (中 = 3 bytes, 文 = 3 bytes)
encodeURIComponent('🚀');
// → "%F0%9F%9A%80" (rocket emoji = 4 UTF-8 bytes)5. Encoding Hash Fragments on the Server
The fragment (#section) is never sent to the server — it is client-side only. Encoding or processing it server-side is pointless.
6. Using Deprecated escape() in JavaScript
The escape() function is deprecated and does not handle UTF-8 properly. Always use encodeURI() or encodeURIComponent() instead.
// DEPRECATED — do NOT use
escape('hello world'); // → "hello%20world" (works for ASCII)
escape('café'); // → "caf%E9" (WRONG! not UTF-8)
// CORRECT alternatives
encodeURIComponent('café'); // → "caf%C3%A9" (correct UTF-8)When to URL Encode: Query Params, Path Segments, Fragment
Different parts of a URL have different encoding rules:
// URL anatomy and encoding zones
https://user:pass@example.com:8080/path/to/page?key=value&k2=v2#section
|____| |_______| |__________| |__||____________||________________||______|
scheme userinfo host port path query string fragment
// Each part has different encoding rules:Query Parameters
Always encode parameter keys and values. This is the most common place where encoding is needed.
// Query parameters: ALWAYS encode keys and values
const params = new URLSearchParams();
params.set('search', 'C++ programming'); // auto-encodes
params.set('filter', 'price>100&sale=true'); // auto-encodes
params.toString();
// → "search=C%2B%2B+programming&filter=price%3E100%26sale%3Dtrue"
// Or manually:
'?q=' + encodeURIComponent('price > $100 & discount = 20%')
// → "?q=price%20%3E%20%24100%20%26%20discount%20%3D%2020%25"Path Segments
Encode each path segment individually. Forward slashes (<code>/</code>) that are part of the URL structure should NOT be encoded, but slashes within a segment value must be.
// Path segments: encode each segment individually
const fileName = 'my report (final).pdf';
const path = '/files/' + encodeURIComponent(fileName);
// → "/files/my%20report%20(final).pdf"
// DO NOT encode the structural slashes:
// WRONG: encodeURIComponent('/files/my report.pdf')
// → "%2Ffiles%2Fmy%20report.pdf" (broken path)Fragment Identifier
The fragment (after <code>#</code>) follows the same encoding rules as query strings. Note that fragments are never sent to the server.
// Fragment: encode like query string values
const section = 'Q&A Section';
const url = '/page#' + encodeURIComponent(section);
// → "/page#Q%26A%20Section"
// Remember: browsers never send fragments to the server
// window.location.hash gives you the raw fragmentDomain Name (Hostname)
Domain names use Punycode (not percent encoding) for internationalized domain names (IDN). For example, muenchen.de with an umlaut becomes xn--mnchen-3ya.de.
// International Domain Names use Punycode, NOT percent encoding
// münchen.de → xn--mnchen-3ya.de
// 中文.com → xn--fiq228c.com
// 日本語.jp → xn--wgv71a309e.jp
// In JavaScript:
const url = new URL('https://münchen.de/path');
url.hostname; // → "xn--mnchen-3ya.de" (auto-converted)Frequently Asked Questions
What is the difference between %20 and + for spaces?
Both represent a space, but they come from different standards. %20 is defined by RFC 3986 (URI standard) and is used in path segments and modern APIs. + is defined by the application/x-www-form-urlencoded format (HTML forms). In query strings, most servers accept both. For maximum compatibility, use %20.
Should I encode forward slashes (/) in URL paths?
Only if the slash is part of a data value, not a path separator. For example, if a filename contains a slash, it must be encoded as %2F in the path segment. The structural slashes that separate path segments should never be encoded.
How do I encode Unicode characters (e.g., Chinese, Arabic) in URLs?
First convert the character to its UTF-8 byte sequence, then percent-encode each byte. For example, "café" → UTF-8 bytes 63 61 66 C3 A9 → the é becomes %C3%A9. Modern programming languages handle this automatically with their URL encoding functions.
Is URL encoding case-sensitive?
The hexadecimal digits in percent encoding are case-insensitive (%2f and %2F are equivalent). However, RFC 3986 recommends using uppercase letters (%2F) for consistency and normalization.
Do I need to encode the entire URL or just parts of it?
Never encode an entire URL at once. Encode only the individual components — query parameter values, path segments containing special characters, and fragment identifiers. The structural characters (://, /, ?, =, &) must remain unencoded to preserve the URL structure.
URL encoding is a fundamental skill for web development. Keep this reference table handy for quick lookups, and use our tool to encode and decode URLs in real time.