What is URL Encoding?

URL encoding (percent-encoding) is a mechanism for representing characters that are either not allowed in a URL, or that have a special syntactic meaning and need to be treated as literal data rather than URL syntax. Each such character is replaced by a percent sign (%) followed by two hexadecimal digits representing the character's UTF-8 byte value.

For example:

  • Space → %20
  • & (ampersand) → %26
  • = (equals) → %3D
  • + (plus) → %2B
  • / (forward slash) → %2F

RFC 3986: The URL Standard

The authoritative specification for URIs (Uniform Resource Identifiers, the superset of URLs) is RFC 3986, published in 2005 and still current. It defines the URI syntax, the allowed character sets, and when percent-encoding is required.

URLs have a defined structure: scheme://authority/path?query#fragment. Each component has specific rules about which characters are allowed. Characters that do not fit those rules must be percent-encoded.

Reserved vs Unreserved Characters

RFC 3986 divides characters into two main groups:

Unreserved Characters

These can always appear in a URL without encoding. They are: uppercase and lowercase letters (A–Z, a–z), digits (0–9), hyphen (-), underscore (_), period (.), and tilde (~).

Reserved Characters

These have special syntactic meaning in URLs and must be percent-encoded when used as literal data:

CharacterURL MeaningPercent-Encoded
:Separates scheme from authority%3A
/Path separator%2F
?Starts query string%3F
#Starts fragment%23
&Separates query parameters%26
=Separates key from value in query%3D
+Space in form data%2B
@Separates userinfo from host%40

How Percent-Encoding Works

Percent-encoding converts each character to its UTF-8 byte representation, then formats each byte as %XX where XX is the uppercase hexadecimal value of the byte.

For ASCII characters (code points 0–127), the UTF-8 byte is the same as the ASCII code. For example:

  • Space (ASCII 32, hex 20) → %20
  • ! (ASCII 33, hex 21) → %21
  • @ (ASCII 64, hex 40) → %40

For multi-byte Unicode characters, each UTF-8 byte is encoded separately. The euro sign € (U+20AC) encodes as three UTF-8 bytes E2 82 AC, giving %E2%82%AC.

Hex reference: You can look up any character's UTF-8 byte value in the ASCII table or Unicode charts. The pattern %XX always uses uppercase hex letters (A–F), though decoders should accept lowercase too (RFC 3986 recommends uppercase for consistency).

Query Strings and Parameters

The query string is the part of a URL after the ?. It contains key-value pairs separated by &:

https://example.com/search?q=hello+world&sort=date&order=desc

When a query parameter value contains reserved characters, those characters must be percent-encoded. Consider a search for "price > $10 & colour = blue":

https://example.com/search?q=price+%3E+%2410+%26+colour+%3D+blue

The >, $, &, and = in the search term are all encoded because they would otherwise be misinterpreted as URL syntax.

Form Data Encoding

When an HTML form is submitted with method="GET" or as application/x-www-form-urlencoded (the default for POST forms), browsers use a slightly different encoding from standard percent-encoding:

  • Spaces are encoded as + rather than %20
  • All other special characters are percent-encoded as normal

This is defined by the URL living standard and the original HTML form specification. The +-for-space convention applies only in application/x-www-form-urlencoded context — in regular URL paths, + is a literal plus sign.

This is a common source of bugs: a backend that decodes + as a space may work fine for form submissions but fail when processing URLs where + should be a literal plus.

Encoding Unicode Characters

Modern URLs can include non-ASCII characters (known as IRIs — Internationalized Resource Identifiers). However, for maximum compatibility, non-ASCII characters should be percent-encoded using their UTF-8 byte sequences.

Example: encoding the Japanese word 日本 (Nihon):

  • 日 (U+65E5): UTF-8 bytes E6 97 A5 → %E6%97%A5
  • 本 (U+672C): UTF-8 bytes E6 9C AC → %E6%9C%AC

Result: %E6%97%A5%E6%9C%AC

Modern browsers automatically encode non-ASCII characters in the address bar, so users can type international characters naturally. Server-side code must be prepared to decode UTF-8 percent-encoded sequences correctly.

JavaScript: encodeURI vs encodeURIComponent

JavaScript provides two functions for URL encoding, and choosing the wrong one is a common mistake:

encodeURIComponent() — encodes a single URL component value. It encodes all characters except: A–Z a–z 0–9 - _ . ! ~ * ' ( ). Use this for individual parameter values.

encodeURIComponent("price > $10 & colour = blue")
// Returns: "price%20%3E%20%2410%20%26%20colour%20%3D%20blue"

encodeURI() — encodes a complete URL. It does not encode characters that have syntactic meaning in URLs (: / ? # [ ] @ ! $ & ' ( ) * + , ; =). Use this only for full URL strings where the delimiters must stay intact.

encodeURI("https://example.com/search?q=hello world")
// Returns: "https://example.com/search?q=hello%20world"

The rule of thumb: use encodeURIComponent() for values, encodeURI() for complete URLs. In most real-world scenarios, you want encodeURIComponent().

Common Mistakes

Double-Encoding

Encoding an already-encoded string: %20 becomes %2520 (the % gets encoded). Always check whether input is already encoded before encoding again.

Not Encoding Plus Signs

If a value contains a literal +, encode it as %2B to prevent it being decoded as a space in form-encoding contexts.

Forgetting to Decode

Server-side code that reads URL parameters must decode them. Most frameworks do this automatically, but if you are reading raw request strings, call the appropriate decode function (decodeURIComponent in JavaScript, urllib.parse.unquote in Python, etc.).

Using encodeURI for Component Values

If you use encodeURI() on a parameter value, characters like &, =, and + will not be encoded, breaking the query string structure.

Try It Free — No Signup Required

Encode or decode URL parameters instantly with ToolMasta's free URL Encoder. Handles all special characters and Unicode correctly.

Open URL Encoder