About the URL Decoder
URL decode a string to turn %20, %2F, %C3%A9 and other percent-encoding back into readable text. Paste a full link and you also get a Query parameters table that decodes each value on its own, the quickest way to read a long redirect or tracking URL.
You'll reach for it when reading raw request lines in an access log, checking the redirect_uri and state of an OAuth login, seeing where a link in a newsletter really points, or finding out what a form actually submitted. Bytes are read as UTF-8, and Treat + as space starts switched on, because that's how HTML forms send spaces. All decoding happens in your browser.
- Paste an encoded string or a whole URL into Text or URL to decode. Load sample gives you a search URL whose
redirectparameter is itself an encoded URL. - Decoded text shows the whole input, decoded once.
- If the input contains a
?, or the decoded result does because the whole URL was encoded, the Query parameters table lists every Key and Value. Repeated keys such ascolor=red&color=blueget a row each, and anything after#is left out. - Leave Treat + as space on for query strings and form bodies. Turn it off when a
+is real data, such as the phone number+4930123456or a Base64 value. The table follows the switch too. - An error saying the encoding isn't valid points to a
%without two hex digits after it, or to bytes that don't form UTF-8. The Guide tab lists the usual causes.
Inputcaf%C3%A9+au+laitOutputcafé au laitWith Treat + as space turned off, the result is café+au+lait.
Inputhttps://login.example.com/authorize?client_id=web-app&response_type=code&scope=openid+email+profile&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback%3Flang%3Dja&state=eyJyZXR1cm4iOiIvb3JkZXJzIn0Outputhttps://login.example.com/authorize?client_id=web-app&response_type=code&scope=openid email profile&redirect_uri=https://app.example.com/callback?lang=ja&state=eyJyZXR1cm4iOiIvb3JkZXJzIn0
Query parameters:
client_id web-app
response_type code
scope openid email profile
redirect_uri https://app.example.com/callback?lang=ja
state eyJyZXR1cm4iOiIvb3JkZXJzIn0The decoded line is hard to split by eye, because redirect_uri has its own ?. The table decodes each parameter separately. The state value is Base64URL, and the Base64 Decoder shows it holds {"return":"/orders"}.
Inputname%3DJos%25C3%25A9Outputname=Jos%C3%A9Seeing %C3%A9 after decoding means there's a second layer. Paste the result back in to get name=José.
How URL decoding works
Each % and the two hex digits after it stand for one byte. The decoder collects those bytes and reads them as UTF-8, the encoding RFC 3986 recommends and every current browser uses. %C3%A9 is two bytes that form é; %E2%82%AC is three bytes that form €. Characters that weren't encoded pass through unchanged.
Some input can't be decoded, and you get an error instead of a guess:
- A bare
%, as in50% off. The sender should have written%25, which makes it50%25%20off. - A
%followed by something that isn't hex, such as%G1. - Half a character:
%C3alone is the first byte oféwith the second one missing, often because a URL was cut at a length limit. %E9, which is how some old systems sentéin Latin-1 or Windows-1252. On its own that byte isn't valid UTF-8.%u00E9, written by JavaScript's oldescape()function. It isn't part of any URL standard;unescape()in a browser console can read it.
Is + a space or a plus sign?
In application/x-www-form-urlencoded data, which HTML forms send and most query strings follow, + stands for a space. Anywhere else in a URL it's an ordinary plus sign. JavaScript's decodeURIComponent keeps + as it is while URLSearchParams turns it into a space, and mixing the two is a classic bug.
A real case: a client puts a phone number in a query string without encoding it, phone=+4930123456. The server decodes it as form data and gets phone= 4930123456, with a space where the plus was. Clients have to send a real plus as %2B. Keep Treat + as space on to see what the server sees, and turn it off to read the raw value.
Sequences you'll see in logs
A cheat sheet for reading encoded request lines without decoding every one:
%20space,%2Bplus,%25percent sign.%2F/,%3A:,%3F?,%3D=,%26&,%23#. Several of these together usually mean a whole URL was passed as a parameter.%2Ccomma,%22double quote,%27single quote.%C3plus one more byte: an accented Latin letter, such as%C3%A9é or%C3%BCü.%E2%80%99: the curly apostrophe ’ that phones and word processors put in place of'.%C2%A0: a non-breaking space, usually copied from a web page or a document.%F0%9F: the start of an emoji, for example%F0%9F%91%8B👋.%3C,%3E,%00and%0D%0A:<,>, a null byte and a line break. Seen together in a log, they often mean someone is probing for injection bugs.
Double-encoded URLs
When the output still contains %20, %3A or %2F, the string was encoded twice: %2520 decodes to %20, and only a second pass gives the space. Paste the result back into the box to remove one more layer.
Decode again only when you know a second layer exists. A value can legitimately contain %25 meaning a real percent sign, and an extra decode changes the data. Attackers count on that mistake: a filter that decodes once can miss %252e%252e%252f, which becomes ../ after a second decode.
URL decode in code
Note which functions turn + into a space and which keep it.
decodeURIComponent("caf%C3%A9%20au%20lait"); // 'café au lait', keeps +
new URLSearchParams("q=caf%C3%A9+au+lait").get("q"); // 'café au lait'from urllib.parse import unquote, unquote_plus, parse_qs
unquote("caf%C3%A9%20au%20lait") # 'café au lait', keeps +
unquote_plus("caf%C3%A9+au+lait") # 'café au lait'
parse_qs("color=red&color=blue") # {'color': ['red', 'blue']}rawurldecode("caf%C3%A9+au+lait"); // 'café+au+lait', keeps +
urldecode("caf%C3%A9+au+lait"); // 'café au lait'url.PathUnescape(s) // keeps + as +
url.QueryUnescape(s) // + becomes a space
url.ParseQuery("color=red&color=blue")URLDecoder.decode(s, StandardCharsets.UTF_8); // + becomes a spaceUri.UnescapeDataString(s); // keeps + as +
WebUtility.UrlDecode(s); // + becomes a spaceWhat does %20 mean in a URL?
%20 is an encoded space. A URL can't contain a literal space, so the byte 0x20 is written as %20. In query strings and form data you'll also see + used for a space.
Why do I get an error that the URL encoding is not valid?
Every % must be followed by two hex digits, and the bytes must form valid UTF-8. A plain % in the text, like 50%, or a sequence that was cut in half causes the error. The sender should have written a literal percent sign as %25.
Why do I still see %20 or %3A after decoding?
The string was encoded twice, so decode the result once more. To stop it happening, find the place in your code that encodes an already encoded value; the URL Encoder shows what a single correct pass looks like.
Why are plus signs turned into spaces?
In form data and most query strings, + stands for a space, so Treat + as space is on by default. Switch it off if your plus signs are real, for example in a phone number or in a Base64 value.
Can it decode URLs encoded in Latin-1 or Windows-1252?
No. It expects UTF-8, which browsers and modern servers use. Old systems sometimes sent é as %E9; that byte alone isn't valid UTF-8, so you'll see an error. Python's unquote(s, encoding="latin-1") can read such strings.
How do I see all query parameters of a URL?
Paste the full URL. The Query parameters table shows every key and value, decoded, with repeated keys on separate rows. Anything after # is the fragment, which isn't part of the query and isn't sent to the server.
Is it safe to paste a URL with a token or a reset code in it?
Password reset links, magic login links and OAuth callbacks carry one-time codes in the query string. They're decoded in this tab and not uploaded, but anyone who sees the decoded link could use the code until it expires. If a parameter holds a JWT, the JWT Decoder shows its claims.