Free · No sign-up · Runs entirely in your browser, nothing sent to a server
Percent-encode a value or a whole URL, or decode one back to readable text — with both encoding forms shown so you can take whichever you need.
A URL is a compact instruction, and several characters inside it have jobs. The ? starts the query string, & separates parameters, = joins a name to its value, / divides path segments and # marks a fragment.
So what happens when your data contains one of those characters? Without encoding, the browser cannot tell the difference between a separator and a literal character.
Percent-encoding removes the ambiguity. Each byte that could be misread is written as % plus its two-digit hexadecimal value, which no parser will mistake for a separator.
JavaScript provides two encoding functions, and they are not interchangeable. Nearly every URL-encoding problem traces back to using the wrong one.
| encodeURIComponent | encodeURI | |
|---|---|---|
| Use it for | A single value — one parameter, one path segment | A complete URL you want to make safe |
| Escapes : / ? & = # | Yes | No — they are structural |
| Escapes spaces | Yes, to %20 | Yes, to %20 |
| Leaves alone | A–Z a–z 0–9 - _ . ! ~ * ' ( ) | The above plus all reserved characters |
The tool above encodes as a component by default, because encoding a value is the more common need — and it shows the whole-URL result underneath whenever the two differ, so you can take whichever fits.
RFC 3986 divides characters into groups. Unreserved characters are always safe and never need escaping; reserved characters carry meaning and must be escaped when used as data.
| Group | Characters | Behaviour |
|---|---|---|
| Unreserved | A–Z a–z 0–9 - . _ ~ | Never need encoding |
| Reserved — general | : / ? # [ ] @ | Structural; escape when used as data |
| Reserved — sub-delimiters | ! $ & ' ( ) * + , ; = | Meaningful within components |
| Everything else | Space, quotes, < > % { } | \ ^ `, all non-ASCII | Must be encoded |
| Character | Encoded | Why it matters |
|---|---|---|
| space | %20 | The one everybody has seen |
| ! | %21 | Sub-delimiter |
| # | %23 | Otherwise starts the fragment |
| $ | %24 | Sub-delimiter |
| % | %25 | Must be escaped or everything breaks |
| & | %26 | Otherwise separates parameters |
| + | %2B | Otherwise may be read as a space |
| , | %2C | Sub-delimiter |
| / | %2F | Otherwise divides path segments |
| : | %3A | Separates scheme from the rest |
| = | %3D | Otherwise joins a name to a value |
| ? | %3F | Otherwise starts the query string |
| @ | %40 | Common in email parameters |
Paste any of these into the encoder above. Every value was generated and verified rather than typed.
| What it is | Raw value | Encoded as a component |
|---|---|---|
| Search query | fish & chips near me | fish%20%26%20chips%20near%20me |
| Email address | name+tag@example.com | name%2Btag%40example.com |
| Product name | Men's 50% Cotton T-Shirt (L/XL) | Men's%2050%25%20Cotton%20T-Shirt%20(L%2FXL) |
| City with spaces | Sunshine Coast, QLD | Sunshine%20Coast%2C%20QLD |
| JSON value | {"filter":"price<100"} | %7B%22filter%22%3A%22price%3C100%22%7D |
| Date range | 2026-07-01/2026-07-31 | 2026-07-01%2F2026-07-31 |
| Path as a value | /misc/internet/url-encode-decode.html | %2Fmisc%2Finternet%2Furl-encode-decode.html |
| Text with emoji | G'day 🇦🇺 | G'day%20%F0%9F%87%A6%F0%9F%87%BA |
Assembling a real query string. Each value is encoded separately, then joined with the separators left intact:
This one catches people repeatedly, because two different standards are in play.
| Context | A space becomes |
|---|---|
| Percent-encoding (RFC 3986) | %20 |
| HTML form submission (application/x-www-form-urlencoded) | + |
Both are legitimate in their own context, but a standard decoder only understands the first. Run hello+world through decodeURIComponent and you get hello+world back, plus sign intact — because in a URL path a + is a literal plus, not a space.
Percent-encoding works on bytes, not characters, so any non-ASCII text is converted to UTF-8 first. Each resulting byte then gets its own escape sequence.
| Character | UTF-8 bytes | Encoded |
|---|---|---|
| a | 1 | a — unreserved, left alone |
| é | 2 | %C3%A9 |
| 語 | 3 | %E8%AA%9E |
| 😀 | 4 | %F0%9F%98%80 |
This is why an encoded URL containing non-English text looks so much longer than the original — a single Japanese character costs nine characters once encoded. Modern browsers display internationalised URLs in readable form while sending the encoded version, which is why the address bar and a copied link often look different.
| Symptom | Usual cause |
|---|---|
| %2520 appearing in URLs | Double encoding — the string was encoded twice, so the % of %20 became %25 |
| A parameter truncated at an ampersand | The value contained & and was not encoded as a component |
| Spaces arriving as plus signs | Form-encoded data decoded with a percent-only decoder |
| An email address breaking a link | The + in name+tag@example.com read as a space |
| Everything after # disappearing | An unescaped hash — the server never sees the fragment at all |
| A whole URL turned into gibberish | encodeURIComponent applied to a complete URL |
| Language | Encode a value | Decode |
|---|---|---|
| JavaScript | encodeURIComponent(s) | decodeURIComponent(s) |
| JavaScript (whole URL) | encodeURI(s) | decodeURI(s) |
| Python | urllib.parse.quote(s, safe='') | urllib.parse.unquote(s) |
| Python (form data) | urllib.parse.quote_plus(s) | urllib.parse.unquote_plus(s) |
| PHP | rawurlencode($s) | rawurldecode($s) |
| PHP (form data) | urlencode($s) | urldecode($s) |
The question is rarely "should I encode?" — it is almost always yes. The real question is which of the two functions applies.
| Situation | Encode | Why |
|---|---|---|
| REST API query parameter | Component | The value may contain & or =, which would otherwise be read as structure |
| Search terms | Component | Free text can contain literally anything |
| Path segment | Component | A slash inside the value would create a fake directory level |
| OAuth redirect_uri | Component | You are putting a whole URL inside another URL — this is the classic case for component encoding |
| Redirect target in a link | Component | Same reason: a URL carried as a value |
| Fixing spaces in an existing URL | Whole URL | The structure is already correct and must survive |
| A URL from user input, for display | Whole URL | You want it usable as a link, not flattened into a string |
| HTML form submission | Handled for you | The browser encodes it — but note it uses + for spaces |
What is URL encoding?
URL encoding, also called percent-encoding, replaces characters that are unsafe or have special meaning in a URL with a percent sign followed by two hexadecimal digits. A space becomes %20 and an ampersand becomes %26. It exists so that data inside a URL cannot be mistaken for the URL's own structure.
What does %20 mean?
It is an encoded space. The hexadecimal number 20 is 32 in decimal, which is the ASCII code for a space character. Spaces are not permitted in URLs, so every space in a web address is transmitted as %20 — or as a plus sign if the data came from an HTML form.
What is the difference between encodeURI and encodeURIComponent?
encodeURIComponent escapes everything that is not unreserved, including : / ? & = and #, which makes it correct for a single parameter value. encodeURI leaves those structural characters intact, which makes it correct for a complete URL. Using encodeURIComponent on a whole URL mangles it; using encodeURI on a value that contains an ampersand breaks the query string.
Why do spaces sometimes become plus signs?
Because HTML form submissions use a different convention. The application/x-www-form-urlencoded format sends spaces as +, while percent-encoding uses %20. Standard decoders only understand %20, so a plus sign survives decoding as a literal plus. Whether it should become a space depends entirely on where the string came from.
Which characters must be URL encoded?
Everything except the unreserved set — letters, digits, hyphen, full stop, underscore and tilde. Reserved characters such as : / ? # [ ] @ ! $ & ' ( ) * + , ; = must be encoded whenever they appear as data rather than as structure. Spaces, quotes and all non-ASCII characters always need encoding.
Why do I see %2520 in a URL?
That is double encoding. A space became %20 on the first pass, then the percent sign itself was encoded as %25 on the second, giving %2520. It means the value was encoded twice somewhere in your pipeline. Encode exactly once, at the point where you assemble the URL.
What is the difference between a URL and a URI?
A URI is any identifier for a resource; a URL is a URI that also says how to locate it, by including a scheme such as https. In everyday use the terms are interchangeable, and the encoding rules in RFC 3986 apply to both.
How are emoji and non-English characters encoded?
They are converted to UTF-8 bytes first, and each byte becomes its own escape sequence. An accented character such as é takes two bytes and encodes to %C3%A9; a Japanese character takes three and becomes something like %E8%AA%9E; an emoji takes four. This is why encoded URLs containing non-English text look so much longer than the original.
Is URL encoding secure?
No. It is fully reversible by anyone and provides no confidentiality at all — it is a transport convention, not a protection mechanism. It is also not sanitisation: encoded data still needs proper escaping before being inserted into HTML, SQL or a shell command. Never put tokens or passwords in a URL, since URLs appear in logs, browser history and referrer headers.
Why does my URL break at the hash symbol?
Because # marks the start of a fragment, which browsers handle locally and never send to the server. An unescaped hash inside a parameter value means everything after it is silently discarded before the request is even made. Encode it as %23 and the whole value arrives intact.
Do I need to encode an email address in a URL?
Usually yes, as a component. The @ becomes %40, and the + used in tagged addresses such as name+tag@example.com becomes %2B — otherwise it may be interpreted as a space and the address arrives wrong. Encoding the value properly avoids both problems.
Is this tool safe to use?
It runs entirely in your browser using the standard encodeURIComponent and decodeURIComponent functions. Nothing is transmitted, logged or stored — disconnect from the internet and it still works. That said, remember that encoding provides no protection: if the data is sensitive, encoding it changes nothing about who can read it.
Almost every URL-encoding problem comes down to two decisions: whether you are encoding a value or a whole URL, and making sure it happens exactly once. Get those right and the rest follows.
The related tool worth knowing is the Base64 encoder and decoder, which solves the neighbouring problem of moving binary data through text-only channels. Both are encoding rather than encryption, and neither protects anything.