How to use it
There are two tools on this page. The one at the top encodes or decodes a string. The one below it, “URL structure parser”, takes one complete URL and shows it part by part. Neither affects the other.
For the top one, choose “Encode” or “Decode” under “Direction”, then set two things.
- Encoding type: “Single value” is for a piece you’re going to slot into a URL, such as the value of a query parameter. “Whole URL” is for a string that already has the shape of an address. The next section explains the difference.
- + as space (application/x-www-form-urlencoded): turn it on only when you’re working with data submitted by an HTML form.
When encoding, what you type in “Original text” comes out in “Encoded result”. When decoding, “Encoded string” becomes “Decoded result”. Encoding € gives %E2%82%AC. This character is 3 bytes in UTF-8, so it turns into three %XX groups. “Send result to decode input” and “Send result to encode input” move the result you just got into the input of the opposite direction.
“Single value” and “Whole URL” leave different characters alone
Both types replace characters that can’t appear in a URL as they are with % followed by two hex digits (percent-encoding). Where they differ is in how they handle the characters that divide a URL into its parts, such as /, ?, and &. “Single value” gives the same result as JavaScript’s encodeURIComponent, and “Whole URL” the same as encodeURI.
| Encoding type | Characters left unchanged |
|---|---|
| Single value | letters, digits, - _ . ! ~ * ' ( ) |
| Whole URL | all of the above plus ; / ? : @ & = + $ , # |
Take the same input, https://example.com/café?q=crème brûlée&page=1#menü, and the two types part ways like this.
- Whole URL:
https://example.com/caf%C3%A9?q=cr%C3%A8me%20br%C3%BBl%C3%A9e&page=1#men%C3%BC - Single value:
https%3A%2F%2Fexample.com%2Fcaf%C3%A9%3Fq%3Dcr%C3%A8me%20br%C3%BBl%C3%A9e%26page%3D1%23men%C3%BC
The first works as an address right away. The second doesn’t, but it can go into another URL whole as a parameter value (?redirect=...). In the other direction, if you put the search term a/b&c into a query value using “Whole URL”, the & is left in place and gets read as the start of the next parameter. That’s when you need “Single value”, which produces a%2Fb%26c.
Decoding has the same split. “Whole URL” doesn’t undo the encoding of the characters that divide a URL. Give it a%2Fb%3Fc%26d%23e%20f and “Single value” returns a/b?c&d#e f, while “Whole URL” returns a%2Fb%3Fc%26d%23e f. If you decode something and %2F or %26 is still there, try switching the encoding type to “Single value”.
One thing worth remembering: even “Single value” leaves ! ' ( ) * unchanged. If the value is going to a server that insists on those being encoded too, replace them in the result yourself with %21, %27, %28, %29, and %2A.
+ as space
Data sent by an HTML <form> (application/x-www-form-urlencoded) writes a space as +, not %20. Turn on “+ as space” when you’re producing or reading that format.
| Direction | Input | Option off | Option on |
|---|---|---|---|
| Encode (Single value) | a+b c |
a%2Bb%20c |
a%2Bb+c |
| Encode (Whole URL) | a+b c |
a+b%20c |
a%2Bb+c |
| Decode (Single value) | a+b%2Bc |
a+b+c |
a b+c |
With the option on, a + that was in the original becomes %2B so it can’t be mistaken for a space. “Whole URL” normally leaves + alone, but with this option on it changes it to %2B in the same way. When decoding with the option off, + is just +. If you decode a value copied from a search results address, such as q=crème+brûlée, and the + is still there, that’s a case for turning the option on. In a URL path or a file name + doesn’t mean a space, so leave it off there.
What the URL structure parser shows
Enter a complete URL that starts with a protocol such as https:// in the “Full URL” field and you get “Protocol”, “Host”, and “Path”, plus “Query string” and “Hash” when the URL has them. The table underneath lists the query parameters one per row as “Key” and “Value (decoded)”. Without a protocol, as in example.com/path, you see “This isn’t a complete URL with a protocol (like https://).”
The values shown are not your input character for character. They’re what the browser has after parsing and normalizing the URL. Enter https://Example.COM:443/a/../b/café?q=hello%20world&tag=a&tag=b&x=1+2#top and you get the following.
| Item | Value shown | How it differs from the input |
|---|---|---|
| Protocol | https |
|
| Host | example.com |
lowercased, and 443, the default port for https, is dropped |
| Path | /b/caf%C3%A9 |
/a/.. is resolved and é appears in encoded form |
| Query string | ?q=hello%20world&tag=a&tag=b&x=1+2 |
same as the input |
| Hash | #top |
The table has four rows: q = hello world, tag = a, tag = b, and x = 1 2. A key that appears more than once gets a row each time. As the value of x shows, this table always reads + as a space, whatever the “+ as space” checkbox at the top is set to. That’s because the URL standard’s rule is to parse a query string as form data.
Two more things to know. A domain name with non-ASCII characters appears in “Host” as Punycode (https://café.example/ → xn--caf-dma.example). And when an address carries a username and password, as in http://user:pw@host:8080/p, that part isn’t shown under any item, and “Host” shows only host:8080.
Input that fails to decode
Decoding succeeds only when every % is followed by two hex digits and the bytes they add up to form UTF-8 characters. If anything is off, there’s no result, just a message that begins “The percent-encoding isn’t valid.”
| Input | Why it fails |
|---|---|
100% |
Nothing follows the %. A literal percent sign has to be written as %25 |
%zz |
zz isn’t a hex number |
%E2%82 |
The last byte of the 3-byte character € (%E2%82%AC) is missing. This happens when a long address is copied only partway |
Encoding never fails. Input that can’t stand as a character on its own, like half of an emoji, is encoded as the replacement character (%EF%BF%BD) and doesn’t raise an error.
