How percent-encoding works
Percent-encoding (RFC 3986, section 2.1) has three steps. First the character is converted to bytes with UTF-8. Then each byte is written as % plus two hex digits. Then the codes are joined. ASCII characters are one byte, so a space (byte 20) is %20. Other characters use two to four bytes:
| Character | Code point | UTF-8 bytes | Percent-encoded |
|---|---|---|---|
| space | U+0020 | 20 | %20 |
| % | U+0025 | 25 | %25 |
| é | U+00E9 | C3 A9 | %C3%A9 |
| € | U+20AC | E2 82 AC | %E2%82%AC |
| م (Arabic meem) | U+0645 | D9 85 | %D9%85 |
| 😀 | U+1F600 | F0 9F 98 80 | %F0%9F%98%80 |
Pick Encode to see this table for your own text, or Decode to see which bytes each %XX group contains and which character they form.
Reserved and unreserved characters
RFC 3986 sorts characters into three groups:
| Group | Characters | Rule |
|---|---|---|
| Unreserved | A-Z a-z 0-9 - . _ ~ | Never need encoding. Encoding them is allowed but pointless. |
| Reserved: gen-delims | : / ? # [ ] @ | Structure the URL. Encode them when they are part of a value. |
| Reserved: sub-delims | ! $ & ' ( ) * + , ; = | Separate parts inside a component. Encode them when they are data. |
| Everything else | space, " % < > \ ^ ` { | }, all non-ASCII | Must always be encoded. |
The codes you will meet most often
| Char | Code | Char | Code | Char | Code | Char | Code |
|---|---|---|---|---|---|---|---|
| space | %20 | ! | %21 | " | %22 | # | %23 |
| $ | %24 | % | %25 | & | %26 | ' | %27 |
| ( | %28 | ) | %29 | + | %2B | , | %2C |
| / | %2F | : | %3A | ; | %3B | < | %3C |
| = | %3D | > | %3E | ? | %3F | @ | %40 |
| [ | %5B | \ | %5C | ] | %5D | ^ | %5E |
| ` | %60 | { | %7B | | | %7C | } | %7D |
Upper or lower case hex?
%2f and %2F mean the same byte, but RFC 3986 recommends uppercase, and some systems that compare URLs as plain strings treat the two as different. Signature schemes such as OAuth 1.0 and AWS Signature require uppercase. Use the URL encoder to choose the case.
Percent-encoding is not encryption
Anyone can decode %XX codes. They protect the structure of a URL, not its secrecy, so never rely on them to hide a password or a token. Related encodings are different: HTML entities (&) are for web page text, and Base64 is for binary data.
See also the URL decoder, the encodeURI vs encodeURIComponent comparison and the URL encoding guide.