How to Decode a URL Encoded String (%20 and More Explained)
Decode URL encoded strings like %20 and %3A online or in JavaScript, Python, Java and C#. Learn encodeURIComponent, + vs %20 and query strings.
To decode a URL encoded string, paste it into our URL encode/decode tool and choose Decode. Sequences like %20, %3A and %2F turn back into a space, : and /, and non-English text such as %E0%A4%A8 turns back into the original letters. To go the other way, choose Encode to make text safe for a URL or query string. It all runs in your browser.
Here is what those percent signs mean, and how to encode and decode URLs in JavaScript, Python, Java and C#.
What URL encoding is
URLs can only contain a limited set of characters: letters, digits and a few symbols like -, _, . and ~. Some other characters have special jobs:
| Character | Job in a URL |
|---|---|
/ |
Separates path segments |
? |
Starts the query string |
& |
Separates query parameters |
= |
Separates a parameter name from its value |
# |
Starts the fragment (a position in the page) |
+ |
Means a space in form-encoded query strings |
% |
Starts an encoded character |
To include any other character, or to use one of these as ordinary data, it is percent-encoded: replaced by % followed by its byte value in hexadecimal. This is also called URL encoding.
Common encoded characters
| Character | Encoded |
|---|---|
| Space | %20 (or + in form data) |
! |
%21 |
" |
%22 |
# |
%23 |
% |
%25 |
& |
%26 |
+ |
%2B |
/ |
%2F |
: |
%3A |
= |
%3D |
? |
%3F |
@ |
%40 |
Non-English characters are first converted to UTF-8 bytes, and each byte is encoded. The Hindi letter न is three bytes in UTF-8, so it becomes %E0%A4%A8. That is why a Hindi or emoji URL looks so long when you copy it.
%20 vs +
Both can mean a space, but not everywhere:
%20is a space anywhere in a URL.+is a space only in query strings encoded the way HTML forms do it (application/x-www-form-urlencoded). In a path,+is a literal plus.
Our decoder treats + as a space, which is what you want for query strings and form data. If you are decoding a path that contains a real plus sign, check the result.
Why query strings need encoding
Say you want to pass the value Tom & Jerry as a search parameter:
https://example.com/search?q=Tom & Jerry
The & would be read as the start of a new parameter, and the space breaks the URL. Encoded properly:
https://example.com/search?q=Tom%20%26%20Jerry
The same applies to email addresses, other URLs passed as parameters (like a redirect= value), and anything containing =, ? or #.
encodeURIComponent vs encodeURI (JavaScript)
| Function | Leaves alone | Use for |
|---|---|---|
encodeURI() |
A–Z a–z 0–9 - _ . ! ~ * ' ( ) ; / ? : @ & = + $ , # |
A complete URL you just want to make valid |
encodeURIComponent() |
A–Z a–z 0–9 - _ . ! ~ * ' ( ) |
A single value going into a query string or path segment |
Example:
encodeURIComponent('a&b=c')givesa%26b%3DcencodeURI('a&b=c')givesa&b=c(unchanged)
Our tool uses encodeURIComponent, which is the right choice for individual query parameter values. To decode, JavaScript has decodeURIComponent() and decodeURI(). decodeURIComponent throws a "URIError: URI malformed" if it meets a broken sequence like %E0%A4 (incomplete) or a lone %.
For building query strings, URLSearchParams handles encoding for you:
new URLSearchParams({ q: 'Tom & Jerry', page: 2 }).toString() gives q=Tom+%26+Jerry&page=2.
How to decode a URL encoded string in Python
from urllib.parse import quote, unquote, quote_plus, unquote_plus, urlencode
unquote('hello%20world') # 'hello world'
unquote_plus('hello+world') # 'hello world'
quote('a&b=c', safe='') # 'a%26b%3Dc'
urlencode({'q': 'Tom & Jerry'}) # 'q=Tom+%26+Jerry'
By default quote leaves / unencoded; pass safe='' to encode it too.
In Java and C#
- Java:
URLDecoder.decode(s, StandardCharsets.UTF_8)andURLEncoder.encode(s, StandardCharsets.UTF_8)(Java 10+; older versions take"UTF-8"as a string). These use form encoding, so spaces become+. - C#:
Uri.UnescapeDataString(s)decodes;Uri.EscapeDataString(s)encodes using%20for spaces.WebUtility.UrlDecodeandWebUtility.UrlEncodeuse+for spaces.
Double encoding
If you see %2520 in a URL, the text was encoded twice: %20 was encoded again, and the % became %25. Decode once and you get %20; decode again to get the space. This usually happens when a value is encoded by your code and then again by a library. Encode exactly once, at the point where the value goes into the URL.
URL encoding vs Base64
URL encoding makes text safe for URLs while keeping it mostly readable. Base64 turns any data, including binary, into a compact text form, but it is unreadable and is not URL-safe by default. If you need to put a Base64 string in a URL, use the URL-safe variant or percent-encode its +, / and =. See Base64 encode/decode and our guide on decoding Base64.
If the decoded value is a block of JSON, as often happens with tracking links and API callbacks, paste it into the JSON formatter to read it.
Common mistakes
- Building URLs by gluing strings together without encoding values, which breaks as soon as a value contains
&or a space. - Using encodeURI for a parameter value, leaving
&and=unencoded. - Encoding twice, producing
%2520. - Treating
+as a space in a URL path. It only means a space in form-encoded query strings. - Putting personal data in URLs. Even encoded, it is readable and ends up in browser history and server logs.
Questions
What does %20 mean in a URL?
%20 is a space. URLs cannot contain spaces, so each one is replaced by a percent sign followed by its character code in hexadecimal, which for a space is 20.
What is the difference between %20 and + in a URL?
Both can represent a space. %20 works anywhere in a URL. + means a space only in query strings sent by HTML forms; in the path part of a URL, + is a literal plus sign.
What is the difference between encodeURI and encodeURIComponent?
encodeURI encodes a full URL but leaves characters like / ? & = # alone so the URL still works. encodeURIComponent encodes those too, which makes it right for a single query parameter value.
How do I decode a URL in Python?
Use urllib.parse.unquote('hello%20world') to get 'hello world'. For form data where + means space, use urllib.parse.unquote_plus.