URL Encoder and Decoder
Percent-encode a value, or read back one that is already encoded.
Runs entirely in your browser
Loading the tool…
A URL may only contain a restricted set of ASCII characters. Everything else, from
spaces and accents and emoji to the punctuation that gives a URL its structure, has
to be written as % followed by two hex digits of UTF-8. That is percent
encoding, and it is why a space in a link arrives as %20.
The two modes matter. Component encodes everything unsafe,
including / ? : & =, which is what you want for a single query value
or path segment. Whole address leaves those structural characters
alone so a complete URL stays usable. Encoding a full URL in component mode is the
classic mistake: it turns the whole thing into one unusable string.
How to use it
- Paste your text or encoded string.
- Pick Encode or Decode, and choose whether the input is one value or a whole address.
- Copy the result.
Questions
When do I need component mode instead of whole address?
Use component mode for anything you are putting *into* a URL: a search term, a filename, a redirect target. Use whole-address mode when the input is already a complete URL and you only want the illegal characters fixed.
Why is a space sometimes %20 and sometimes +?
%20 is correct everywhere. The + shorthand is only valid in the query string of HTML form submissions (application/x-www-form-urlencoded). The decoder here has a switch for it, because pasted form data is full of them.
What happens to accents and emoji?
They are encoded as their UTF-8 bytes, so é becomes %C3%A9 and 😀 becomes %F0%9F%98%80. Decoding reverses it exactly, provided the bytes really were UTF-8.
Which characters never need encoding?
The unreserved set from RFC 3986: letters, digits, and the four marks - . _ ~. Anything else is either reserved for the URL syntax or outside ASCII, and a strict encoder will escape it. An encoder that leaves !, * or ( alone is not wrong, just lenient.
How are accented characters and emoji encoded?
As UTF-8 bytes, one percent group each. An accented e is %C3%A9 and a typical emoji is four groups such as %F0%9F%98%80. Older systems sometimes used a different byte encoding for the same character, which is where mojibake in URLs comes from.
encodeURI or encodeURIComponent?
encodeURI expects a whole URL, so it leaves : / ? # [ ] @ intact, because those are doing their job. encodeURIComponent expects one value going into a URL and escapes them. For a query parameter, a path segment or anything user-supplied, you want the second one.
Why does my query string turn plus signs into spaces?
Because form submissions use application/x-www-form-urlencoded, an older encoding where + means a space. It applies to form bodies and, by convention, query strings. In a path a + is a literal plus. A literal plus in a query string has to be sent as %2B, which is why email addresses with tags get mangled so often.
Percent-encoding, character by character
RFC 3986 splits characters into three groups. Unreserved characters,
A-Z, a-z, 0-9 and the four marks
- . _ ~, never need encoding
anywhere in a URL. Reserved characters have a job in the syntax, so they have to be
encoded whenever they appear as data rather than as punctuation. Everything else is
encoded because it cannot be typed safely.
| Char | Code | Why it matters |
|---|---|---|
| space | %20 | Breaks the URL at the first one, in almost every parser |
! | %21 | Safe in practice, encoded by strict encoders |
" | %22 | Ends the attribute if the URL sits in HTML |
# | %23 | Starts the fragment; everything after it never reaches the server |
$ | %24 | Reserved in the path |
% | %25 | Starts an escape, so a literal one must be escaped itself |
& | %26 | Separates query parameters |
' | %27 | Ends the attribute in single-quoted HTML |
+ | %2B | Means a space in form data, so a literal plus must be encoded |
, | %2C | Reserved, and a list separator in some APIs |
/ | %2F | Separates path segments |
: | %3A | Separates scheme from the rest, and host from port |
= | %3D | Separates a parameter name from its value |
? | %3F | Starts the query string |
@ | %40 | Separates credentials from the host |
[ ] | %5B %5D | Wrap an IPv6 address in the host |
Anything outside ASCII is encoded as UTF-8 first, then one escape per byte. So
e with an acute accent is two bytes and becomes %C3%A9, and
an emoji is four bytes and becomes four groups. That is why an encoded URL with
accented words looks so much longer than the text that produced it.
The other direction
Decoding has a page of its own, opening the right way round:
Your data stays on your device
Everything above runs inside your browser as WebAssembly compiled from Rust. Nothing you type is uploaded, logged or stored on a server. You can load this page once, go offline, and it still works.
This page makes no requests at all, to anywhere. That is not a promise in the copy: it is a Content-Security-Policy header your browser enforces, and connect-src on it is none. Open the network tab and watch nothing happen.