URL Encoder and Decoder
Three encodings that are not the same, and a URL taken apart.
Encode and decode URLs three ways, take any address apart into its components, and see exactly where percent encoding and form encoding disagree.
Which encoding
- Characters in
- 50
- Characters out
- 74
- Escaped
- 12
Where the three encodings disagree
| Input | Component | Strict | Form |
|---|---|---|---|
| hello worldA space: %20 in a path, + in a form-encoded query. | hello%20world | hello%20world | hello+world |
| a+bA literal plus. Form decoding turns this back into a space unless it is escaped. | a%2Bb | a%2Bb | a%2Bb |
| it's (fine)encodeURIComponent leaves the apostrophe and brackets alone; strict mode escapes them. | it's%20(fine) | it%27s%20%28fine%29 | it%27s+%28fine%29 |
| 100%A bare percent sign is invalid in a URL and must become %25, or decoding fails. | 100%25 | 100%25 | 100%25 |
| caféNon-ASCII becomes UTF-8 bytes: two escapes for é, not one. | caf%C3%A9 | caf%C3%A9 | caf%C3%A9 |
| 🎉An emoji is four bytes, so four escapes. | %F0%9F%8E%89 | %F0%9F%8E%89 | %F0%9F%8E%89 |
| a/b?c=dStructural characters inside a value must all be escaped. | a%2Fb%3Fc%3Dd | a%2Fb%3Fc%3Dd | a%2Fb%3Fc%3Dd |
The rules underneath
- UnreservedA-Z a-z 0-9 - . _ ~
- Never need encoding, anywhere, and should not be encoded — a server comparing %41 with A may treat them as different.
- Reserved, general delimiters: / ? # [ ] @
- Structural. Safe in the part they delimit and must be encoded when they appear inside a value.
- Reserved, sub-delimiters! $ & ' ( ) * + , ; =
- Used by particular schemes and formats. encodeURIComponent leaves ! ' ( ) * unescaped, which is why the strict mode here exists.
- Everything elsespace, quotes, angle brackets, non-ASCII
- Always encoded, as UTF-8 bytes written in percent-hex. A single emoji becomes four percent-escapes.
Everything runs in this browser, which matters because URLs carry session tokens, reset links and API keys in their query strings far more often than they should. Nothing typed here is sent anywhere.
How the URL Encoder and Decoder works
URL encoding is not one operation. encodeURIComponent leaves five reserved characters alone, a space is %20 in a path and a plus in a query string, and a plus decodes to a space in one and stays a plus in the other. All three are here side by side, because picking the wrong one is where the bugs come from.
Also known as: url decoder online · percent encoding converter · urlencode online · query string parser · encodeuricomponent online
Frequently asked questions
What is the difference between encodeURI and encodeURIComponent?
encodeURI is for a whole URL and leaves the structural characters alone, so the slashes, question mark and ampersands keep working. encodeURIComponent is for one value and escapes those characters, because inside a value they are data rather than structure. Using the first on a value leaves it broken, and using the second on a whole URL destroys the address. Neither escapes ! ' ( ) * which RFC 3986 lists as reserved, which is why a strict mode exists here.
Why is my space sometimes %20 and sometimes a plus?
Because they are two different encodings. Percent encoding, which paths use, writes a space as %20. Form encoding, used for query strings and POST bodies, writes it as a plus — a convention that predates the URL standard and survives in every HTML form. Both appear in the same address routinely, which is why a value copied from a query string into a path arrives with a stray plus in it.
Why does a plus in my query string become a space?
Because form decoding turns it into one, and that is correct for a query string. If the plus is meant literally — in a phone number, or a search for C++ — it has to be written as %2B or it will not survive. This is the single most common URL encoding bug, and it is invisible until somebody searches for something with a plus in it.
Why does decoding fail with a percent sign in the text?
Because a percent must be followed by two hexadecimal digits, so a literal one has to be written as %25. A string containing a bare percent, such as a discount of 100%, is not valid percent encoding at all, and a decoder that throws rather than returning null on it will take an application down. Encoding first, always, is the fix.
What is punycode and why does it matter?
It is how a domain containing non-ASCII characters is stored, as a name beginning xn--. It matters because a name can read as one thing and resolve as another: a Cyrillic a is visually identical to a Latin one and belongs to a different domain entirely, which is the mechanism behind homograph phishing. Any punycode host is flagged here with its ASCII form, since that is what actually resolves.
Is the fragment sent to the server?
No. Everything after the # is handled entirely by the browser and never appears in a request, which is why it is invisible in server logs and why single-page applications used it for routing before the history API existed. It also means a token placed after a # is not logged by the server, which is deliberate in some OAuth flows.
Related calculators
Base64 Encoder and Decoder
Handles emoji and every other script, which most converters cannot.
OpenCSV to JSON Converter
Both directions, with quoting handled the way the spec says.
OpenRegex Tester
Test a pattern, and read what it actually says in English.
Open