URL Encode: Text to Percent-Encoding
percent-encoding
Read a percent-encoded string back as text →
How do you URL encode a string?
URL encoding replaces the characters a URL cannot carry as data. A percent-encoded octet is a triplet: a percent sign followed by the two hexadecimal digits of that byte's value.
A space becomes %20. Percent-encoding replaces every character outside the unreserved set - letters, digits, hyphen, period, underscore and tilde - with a percent sign and that byte's two hex digits.
- Write the text as UTF-8 octets first. That order is what makes a character outside US-ASCII into more than one triplet.
- Leave every unreserved character as it is: A-Z a-z 0-9 - . _ ~.
- Replace every other octet with a percent sign and that octet's 2 hexadecimal digits.
- Check the reserved characters. Each is safe where it delimits and needs a triplet where it is data.
- Read the result back to confirm it. hello world becomes hello%20world.
Text to Percent-Encoding Conversion Table
The reserved characters are the general delimiters : / ? # [ ] @ and the sub-delimiters ! $ & ' ( ) * + , ; = . Each one is safe where it acts as a delimiter and must be percent-encoded where it is data. The unreserved set is the ASCII letters, the digits, hyphen (-), period (.), underscore (_) and tilde (~). These characters never need percent-encoding, and a normaliser decodes them if it finds them encoded. Read the row for the character you have: the Triplet column is what a URL carries in its place. ASCII codes 32–126 are printable characters; 0–31 and 127 are control characters (for example 10 = line feed, 13 = carriage return, 32 = space). That row is the one everybody meets first.
| Character | Name | Role | Triplet |
|---|---|---|---|
| — | A-Z a-z 0-9 - . _ ~ | unreserved | not encoded |
| : | the colon | general delimiter | %3A |
| / | the slash | general delimiter | %2F |
| ? | the question mark | general delimiter | %3F |
| # | the number sign | general delimiter | %23 |
| [ | the left bracket | general delimiter | %5B |
| ] | the right bracket | general delimiter | %5D |
| @ | the at sign | general delimiter | %40 |
| ! | the exclamation mark | sub-delimiter | %21 |
| $ | the dollar sign | sub-delimiter | %24 |
| & | the ampersand | sub-delimiter | %26 |
| ' | the apostrophe | sub-delimiter | %27 |
| ( | the left parenthesis | sub-delimiter | %28 |
| ) | the right parenthesis | sub-delimiter | %29 |
| * | the asterisk | sub-delimiter | %2A |
| + | the plus sign | sub-delimiter | %2B |
| , | the comma | sub-delimiter | %2C |
| ; | the semicolon | sub-delimiter | %3B |
| = | the equals sign | sub-delimiter | %3D |
| (space) | the space | not allowed in a URI | %20 |
| % | the percent sign | starts a triplet | %25 |
The same value in each encoding
These rows are shared with the other encoders, so a value written here is the value every page in the family writes.
| Value | Written as |
|---|---|
| hello world | text 'hello world' = percent 'hello%20world' = base64 'aGVsbG8gd29ybGQ=' |
| space | character ' ' = percent '%20' = base64 'IA==' = HTML no character reference needed |
| ampersand | character '&' = percent '%26' = base64 'Jg==' = HTML & |
| é | character 'é' = percent '%C3%A9' = base64 'w6k=' = HTML é or é |
Every value below is the one the specification fixes, so a result that disagrees with a row here is a result to check. ASCII defines 128 characters, codes 0–127, using 7 bits; in practice each code is stored in one 8-bit byte with a leading 0.
| Attribute | Value |
|---|---|
| triplet form | %HH |
| hex digits per octet | 2 |
| unreserved set | A-Z a-z 0-9 - . _ ~ |
| gen delims | : / ? # [ ] @ |
| sub delims | ! $ & ' ( ) * + , ; = |
| text charset before encoding | UTF-8 |
| defining spec | RFC 3986 |
| percent form of space | %20 |
| percent form of percent | %25 |
| percent form of ampersand | %26 |
| percent form of number sign | %23 |
| percent form of apostrophe | %27 |
| percent form of slash | %2F |
| percent form of colon | %3A |
| percent form of question mark | %3F |
| percent form of equals sign | %3D |
| percent form of plus sign | %2B |
| percent form of left bracket | %5B |
| percent form of right bracket | %5D |
| percent form of at sign | %40 |
| unreserved hyphen | - |
| unreserved period | . |
| unreserved underscore | _ |
| unreserved tilde | ~ |
Worked Example: "hello world" to Percent-Encoding
One character at a time, with the working written out. This is the same grid the converter shows when you turn on "show steps".
percent-encoding
Result: hello world = hello%20world
For characters outside US-ASCII, RFC 3986 says to write the text as UTF-8 octets first and then percent-encode every octet that is not in the unreserved set, which is why é becomes %C3%A9.
Read the grid a row at a time: h is 68 and is written h; e is 65 and is written e; l is 6C and is written l. A character that is already unreserved keeps itself, so most of a readable string passes through untouched and only the characters a URL would misread change at all.
é is U+00E9 and encodes as C3 A9 (2 bytes); € is U+20AC and encodes as E2 82 AC (3 bytes); 😀 is U+1F600 and encodes as F0 9F 98 80 (4 bytes). UTF-8 encodes each character in 1 to 4 bytes. Characters 0–127 use one byte identical to ASCII, so ASCII text is valid UTF-8. Those byte counts are what decide how many triplets a character takes, which is why one character can arrive as two triplets and still be one character when it is read back.
Check it in reverse
Decoding reverses the triplets one byte at a time and then reads the resulting bytes as UTF-8, so two triplets can produce a single character. Read the triplets in the order they appear and the original text comes back whole, because an unreserved character was never changed and a triplet always spells exactly one byte. To verify the result by hand, decode the percent-encoded output back to text and compare it with what you started from.
Worked examples: text to percent-encoding
Each example gives the value first, then the working. Click a value to load it in the converter.
What is a space URL encoded?
Text a space in percent-encoding is %20.
Method: write the character as UTF-8 (20) and give each octet a percent sign and two digits.
What is an ampersand URL encoded?
Text an ampersand in percent-encoding is %26.
Method: write the character as UTF-8 (26) and give each octet a percent sign and two digits.
What is a slash URL encoded?
Text a slash in percent-encoding is %2F.
Method: write the character as UTF-8 (2F) and give each octet a percent sign and two digits.
What is e-acute URL encoded?
Text e-acute in percent-encoding is %C3%A9.
Method: write the character as UTF-8 (C3 A9) and give each octet a percent sign and two digits.
What is a number sign in percent-encoding?
Text a number sign in percent-encoding is %23.
Method: write the character as UTF-8 (23) and give each octet a percent sign and two digits.
What is a question mark in percent-encoding?
Text a question mark in percent-encoding is %3F.
Method: write the character as UTF-8 (3F) and give each octet a percent sign and two digits.
What is an equals sign in percent-encoding?
Text an equals sign in percent-encoding is %3D.
Method: write the character as UTF-8 (3D) and give each octet a percent sign and two digits.
What is a plus sign in percent-encoding?
Text a plus sign in percent-encoding is %2B.
Method: write the character as UTF-8 (2B) and give each octet a percent sign and two digits.
What is a colon in percent-encoding?
Text a colon in percent-encoding is %3A.
Method: write the character as UTF-8 (3A) and give each octet a percent sign and two digits.
What is an at sign in percent-encoding?
Text an at sign in percent-encoding is %40.
Method: write the character as UTF-8 (40) and give each octet a percent sign and two digits.
What is an apostrophe in percent-encoding?
Text an apostrophe in percent-encoding is %27.
Method: write the character as UTF-8 (27) and give each octet a percent sign and two digits.
What is "hello world" in percent-encoding?
Text "hello world" in percent-encoding is hello%20world.
Method: write the text as UTF-8 octets and give every octet outside the unreserved set a percent sign and two digits.
Every example above reverses exactly - read the same triplets back as characters.
What Decides Which Characters Get Encoded?
Is the character data or a delimiter?
That is the whole decision, and only you know it. A slash between path segments is a delimiter and stays; a slash inside a value is data and becomes %2F.
What if the value is already Base64?
Then it may not need a triplet at all. The URL-safe alphabet of RFC 4648 section 5 keeps the first 62 characters and swaps plus for minus (-) and slash for underscore (_), so the result passes through a URL or a file name unchanged.
Has the value been through the encoder twice?
A percent sign is itself percent-encoded as %25, so a string that has been through the encoder twice shows %2520 where one space should be.
What case are the hexadecimal digits?
0b marks binary, 0o octal, 0x hexadecimal; a leading # marks a hex colour. Hexadecimal is not case-sensitive (FF = ff); iToolHub writes hex digits in uppercase.
Is this the encoding you need at all?
The three schemes protect different things and are not interchangeable. these encodings are not interchangeable - when percent-encoding is the right choice sets out which does what.
Text to Percent-Encoding in Code
Both standard libraries carry this conversion, so the one-liner below is the whole job. Check the result against the table above before you trust it in a pipeline.
Python: urllib.parse.quote('hello world', safe='') JavaScript: encodeURIComponent('hello world') Common Mistakes
- Encoding a whole URL rather than one value. The delimiters go too, and the address stops being an address.
- Running the encoder twice. A percent sign is itself percent-encoded as %25, so a string that has been through the encoder twice shows %2520 where one space should be.
- Assuming the space is the only problem. Every character outside the unreserved set needs a triplet, and the reserved ones need one whenever they are data.
Frequently Asked Questions
What is URL encoding?
It is the rule that decides which characters a URL can carry as data. A percent-encoded octet is a triplet: a percent sign followed by the two hexadecimal digits of that byte's value.
Is %20 URL encoding?
Yes. %20 is the percent-encoded form of a space and it is the form this page writes.
Which characters are unreserved in percent-encoding?
The unreserved set — A-Z a-z 0-9 - . _ ~ — and nothing else. Every other character needs a triplet wherever it is data rather than a delimiter.
Should a space become %20 or a plus sign?
Write %20 unless whatever reads the value expects a form's plus convention instead. The two are not interchangeable, so the safe move is to match what the receiving end already does.
How do you URL encode in JavaScript?
encodeURIComponent('hello world') returns hello%20world. Use it for one value; encodeURI leaves the delimiters alone and is for a whole address.
"Can I go back the other way?" Yes. The same value converts straight back in the percent-encoding to text direction.
Related Conversions
The rest of the family sits on the full set of text encoding tools.