URL Encoder & Decoder
Turn text into percent-encoded form, or turn percent-encoded text back into something you can read. Choose whether you are encoding one URL component, a whole address, or form data, and the tool uses your browser’s own encodeURIComponent, encodeURI and URLSearchParams, so the result is exactly what the platform produces. Unicode and emoji survive intact, malformed input gets a plain-English explanation instead of a crash, and nothing you paste is ever sent anywhere.
Query Parameters
Read with your browser’s native URLSearchParams, which follows application/x-www-form-urlencoded rules, so a + is a space in this panel whatever mode is selected above. This is a quick read of the parameters, not a full URL inspector.
| Parameter | Decoded value |
|---|
Your URLs and text stay in your browser. Nothing is uploaded.
What URL Encoding Is
A URL can only carry a small, fixed set of characters safely. Letters, digits and a handful of punctuation marks travel as themselves; everything else has to be rewritten before it can go into an address bar, a query string or an HTTP request. That rewriting is URL encoding, and the format it produces is called percent encoding.
Percent encoding replaces a character with a percent sign followed by two hexadecimal digits. Those two digits are one byte. So a space becomes %20, a forward slash becomes %2F, an ampersand becomes %26 and a percent sign itself becomes %25. Decoding is the reverse: read each %XX back into the byte it stands for, then interpret the bytes as UTF-8 text.
The characters that never need encoding are called unreserved: A–Z, a–z, 0–9, hyphen, period, underscore and tilde. Everything outside that set is either reserved — characters that give a URL its structure, like :/?#[]@!$&'()*+,;= — or simply not allowed at all, like a space, a double quote or an accented letter. Reserved characters are the interesting case, because whether they must be encoded depends on where in the URL they sit. That is the whole reason this tool has more than one mode.
One byte is not always one character. Text is converted to UTF-8 first, and a UTF-8 character can be several bytes long, so it becomes several escapes in a row. é is two bytes and encodes to %C3%A9. An emoji is usually four bytes, so 😀 becomes %F0%9F%98%80. Seeing three or four escapes for a single visible character is normal, not a bug.
When to Encode a URL, and When to Decode One
You encode when you are putting data into a URL, and you decode when you are reading data back out of one. Getting the direction wrong is the most common source of mangled links.
Encode when
- You are building a link whose query string contains user input: a search term, a name, an address, a redirect target.
- A value contains a character that would otherwise change the meaning of the URL, such as
&,=,#,?or+. A search forcats & dogsmust becomecats%20%26%20dogs, or the ampersand will start a second parameter. - A value contains spaces or non-ASCII text. Browsers will often paper over this for you in the address bar, but an HTTP client, an email link or an API call will not.
- You are placing a whole URL inside another URL, as a
redirect_urlornextparameter. The inner URL must be encoded as a single value, colons and slashes included.
Decode when
- You received a URL and need to read it:
%E2%9C%85is not something a human should have to parse by eye. - You are debugging why a request failed and need to see the real parameter values behind the escapes.
- A log, an analytics report or an error message handed you an encoded string and you want the original text back.
- You suspect a value was encoded twice and want to peel one layer off at a time to find out.
The rule that keeps you out of trouble: encode once, at the moment the value enters the URL, and decode once, at the moment it leaves. Every extra pass in either direction is a bug waiting to be found.
URL Component vs Full URL Encoding
These are the two modes people most often mix up, and JavaScript gives them different names: encodeURIComponent() for a piece of a URL, encodeURI() for a whole one. The difference is exactly which reserved characters get left alone.
encodeURI() assumes you are handing it a complete, already-valid address. It escapes spaces, quotes, angle brackets and non-ASCII text, but it deliberately leaves the structural characters untouched — : / ? # & = + , ; @ and $ — because escaping those would destroy the URL’s shape. Encoding https://example.com/a b?x=1&y=2 gives you https://example.com/a%20b?x=1&y=2: the space is fixed, the address still works.
encodeURIComponent() assumes you are handing it one value that is about to be dropped into a larger URL. It escapes the structural characters too, because inside a value they are no longer structure — they are data. The same input becomes https%3A%2F%2Fexample.com%2Fa%20b%3Fx%3D1%26y%3D2, which is correct if that whole string is meant to be a single parameter.
Which one do I want?
- URL Component — a query parameter value, a path segment, a form field, a redirect target, a filename, a search term. This is the default and the one you want most of the time.
- Full URL / URI — an entire address that you are about to paste into a link, an email or a browser, and which contains awkward characters like spaces or accents that need cleaning up without being dismantled.
- Form / Query Data — a query string or a POST body being serialised as
application/x-www-form-urlencoded, where spaces are written as+rather than%20.
A useful way to remember it: if the string you are encoding is a URL, use Full URL. If the string is going into a URL, use URL Component.
%20 or + : How Spaces Get Written
A space is the character that causes the most confusion, because there are two correct answers and they belong to two different standards.
In percent encoding — the RFC 3986 world that encodeURI and encodeURIComponent live in — a space is %20. Always. There is no alternative spelling.
In application/x-www-form-urlencoded — the world of HTML form submissions and of URLSearchParams — a space is written as +, and a literal plus sign is written as %2B. This format predates the modern URL spec and comes from HTML forms, where it is still the default.
So hello world can legitimately appear as either hello%20world or hello+world, and the two are not interchangeable. This is why the tool does not guess. In URL Component and Full URL modes a + is decoded as a literal plus, because in percent encoding that is what it is. Only Form / Query mode reads + as a space, and the hint under the mode selector tells you which rule is currently in force before you rely on the result.
If you decode a form-encoded string in the wrong mode you get hello+world where you expected hello world. If you decode a percent-encoded string as form data you turn every genuine plus sign — C++, a+b, a phone number — into a space. Neither is a crash, which is what makes them easy to miss.
Query Strings and Form Data
A query string is a list of name=value pairs joined by & and introduced by ?. Each name and each value is encoded separately, then assembled. That matters, because encoding the finished string would escape the & and = that hold it together and turn the whole query into one opaque value.
The correct order is: encode each name, encode each value, join with = and &. In JavaScript that is new URLSearchParams({q: term, page: 2}).toString(), which handles the escaping and the + convention for you. Reading one back is new URLSearchParams(location.search).get('q'), or new URL(href).searchParams when you have a full address.
When the text you paste contains something that looks like a query, this tool shows the parameters in a small panel underneath the result, parsed with those same native APIs. It is there to answer “what is actually in this URL?” while you are debugging, and it deliberately stops there. It does not try to be a URL validator, a redirect checker or a developer console. If you want to compare two versions of a long query side by side, Text Compare is the better instrument, and if you need to change every occurrence of one parameter name across a big file, Find & Replace will do it in one pass.
Names can repeat. ?tag=a&tag=b is valid and holds two values for tag, so the panel lists both rows rather than collapsing them. A name with no value at all (?debug) is valid too and appears with an empty value.
Unicode, Emoji and Special Characters
Percent encoding is defined over bytes, not characters, and the bytes come from UTF-8. That single fact explains everything surprising about non-ASCII text in URLs.
An accented letter such as é is two bytes in UTF-8, so it becomes two escapes: %C3%A9. A CJK character is three bytes, so three escapes. An emoji is four bytes, so four escapes: 😀 becomes %F0%9F%98%80. The encoded form is therefore always longer than the original, sometimes by a factor of nine for a four-byte character. If you are checking a value against a length limit, measure the encoded form, not the visible one; the Character Counter will count either string accurately once you have produced it.
Decoding works the same way in reverse, and this is where malformed input shows up. A truncated sequence such as %C3 on its own, or a byte that cannot start a UTF-8 character such as %FF, has no valid interpretation, so decodeURIComponent throws a URIError. This tool catches that, tells you which escape is at fault and where it sits in the string, and leaves your input untouched. The page never breaks and the rest of the tool keeps working.
Right-to-left text, combining marks and zero-width characters all encode and decode correctly, because they are ordinary UTF-8 as far as the browser is concerned. What they do not survive is being cut in half: if a system truncates an encoded string at a fixed byte length it can split a multi-byte escape, and the result will fail to decode. That is a truncation bug upstream, not an encoding one.
Double Encoding, and the %25 Giveaway
Encoding something twice is a classic bug, and it is easy to spot once you know the signature: %25. That escape means “a literal percent sign”, and a percent sign only appears in a URL value if it was already part of an escape the first time round.
Take hello world. Encoded once it is hello%20world. Encode that result again and the % itself gets escaped, giving hello%2520world. Decode once and you are back to hello%20world, which still looks encoded, because it is. Decode a second time and you finally get hello world.
It usually happens when a value is encoded by application code and then encoded again by a framework, a redirect handler or a templating helper that assumes it received raw text. The symptom is a URL that works nowhere, or a search that returns results for the literal string %20.
When you decode something here and the result still contains percent escapes, the tool says so and offers a Decode another layer button. It never loops on its own and never keeps decoding until the escapes run out, because that would silently destroy legitimate data. A value that genuinely contains the text 100% would be chewed up by an over-eager decoder. One layer per click, and you decide whether to take another.
Common URL Encoding Mistakes
- Using
encodeURIon a parameter value. It leaves&,=,#and+alone, so a value containing any of them will break the query around it. Values needencodeURIComponent. - Using
encodeURIComponenton a whole URL. The colons and slashes get escaped and the address stops being an address. Whole URLs needencodeURI. - Encoding an assembled query string. Encode each name and value first, then join them. Escaping the finished string destroys the
&separators. - Assuming
+always means a space. It means a space in form data and a literal plus everywhere else.C%2B%2BisC++;C++in a form query isC. - Replacing spaces with
%20by hand and stopping there. The ampersand, the hash and the percent sign are far more damaging than a space, and a hand-rolled replace will miss them. A hash in an unencoded value truncates the URL at the fragment. - Encoding twice, or decoding twice. Look for
%25. If it is there, something was encoded more than once. - Using uppercase and lowercase hex inconsistently.
%2fand%2Fdecode identically, but they are different strings, so signature checks, cache keys and tests that compare literally will disagree. Browsers emit uppercase. - Trusting the address bar. Browsers encode leniently and invisibly for display, so what you see is not always what was sent. Check the real value, not the pretty one.
If you are trying to find out which of two versions of a URL a server actually received, encode both here and put the results into Text Compare. A single differing escape is much easier to see in percent-encoded form than in the rendered link.
Your URLs Never Leave Your Browser
URL Encoder & Decoder runs entirely in your browser. Encoding and decoding are performed by the JavaScript engine that is already open on your device: the same native encodeURIComponent, decodeURI, URL and URLSearchParams functions the platform uses everywhere else. There is no server call, no upload, no queue and no copy stored anywhere.
That matters more for this tool than for most. URLs carry credentials: session tokens, signed links, password-reset addresses, API keys in query parameters, internal hostnames that were never meant to be public. Pasting one into a web service means trusting that service with it. Here the text goes from the textarea into a local function and back onto the screen, and closing the tab is the end of it.
It also means the tool works offline, responds the instant you type, and has no length limit other than the memory in your device. Nothing is logged, because nothing is transmitted.
Frequently Asked Questions
What is URL encoding?
URL encoding, also called percent encoding, is the way characters that are not safe in a URL get rewritten so they can travel in one. Each unsafe character is converted to its UTF-8 bytes, and each byte is written as a percent sign followed by two hexadecimal digits. A space becomes %20, a slash becomes %2F, an ampersand becomes %26. Letters, digits, hyphen, period, underscore and tilde are left alone. Decoding reverses the process and gives you the original text back.
What is the difference between URL encoding and URL decoding?
They are opposite directions of the same transformation. Encoding takes readable text and produces the percent-encoded form you put into a URL, so hello world becomes hello%20world. Decoding takes a percent-encoded string and produces the readable text behind it, so hello%20world becomes hello world again. You encode when writing a value into a URL and decode when reading one back out. This tool has an Action selector at the top for exactly that choice, and the result updates as you type.
What is the difference between encodeURI and encodeURIComponent?
encodeURI is for a complete address: it escapes spaces, quotes and non-ASCII characters but leaves the structural characters : / ? # & = + , ; @ and $ untouched, so the URL keeps its shape. encodeURIComponent is for one piece of a URL — a parameter value, a path segment, a form field — and it escapes those structural characters too, because inside a value they are data rather than structure. Encoding https://example.com/a b with encodeURI gives https://example.com/a%20b; with encodeURIComponent it gives https%3A%2F%2Fexample.com%2Fa%20b. The Full URL / URI mode here uses the first, and URL Component uses the second.
Should spaces be encoded as %20 or +?
Both are correct, in different contexts. In percent encoding — the standard behind encodeURI and encodeURIComponent — a space is always %20. In application/x-www-form-urlencoded data, which is what HTML forms submit and what URLSearchParams produces, a space is written as + and a real plus sign is written as %2B. They are not interchangeable, so this tool never guesses: URL Component and Full URL modes treat + as a literal plus, and only Form / Query Data mode reads it as a space. The hint under the mode selector always states which rule is active.
Can I encode a complete URL?
Yes — choose Full URL / URI mode, which uses encodeURI. It cleans up the spaces, quotes and non-ASCII characters that would otherwise break a link while leaving the scheme, slashes, query marks and fragment intact, so the result is still a usable address. If instead you want to put a whole URL inside another URL as a parameter value, use URL Component mode so that its colons and slashes are escaped as well and it cannot be mistaken for structure.
Why does my URL contain %20 or %2F?
Because something encoded it. %20 is a space and %2F is a forward slash, and both are characters that cannot appear literally in that position of a URL: a space is not permitted at all, and a slash inside a parameter value would be read as a path separator. Frameworks, redirect handlers, analytics tools and browsers all encode values as they build links, which is why you see these escapes in copied URLs, log files and error messages. Paste the string here in Decode mode with URL Component selected and you will see the original text. If the decoded result still contains %20, look for %25 in the original: that means it was encoded twice.
Can this tool decode Unicode and emoji?
Yes. Encoding converts your text to UTF-8 first, so accented letters, non-Latin scripts, right-to-left text and emoji all round-trip correctly. Because UTF-8 uses more than one byte for these characters, they produce more than one escape: é becomes %C3%A9 and 😀 becomes %F0%9F%98%80. That is expected, not an error. If a sequence is incomplete or is not valid UTF-8 — a lone %C3, or %FF — decoding cannot succeed, and rather than throwing a JavaScript error the tool tells you which escape is at fault and where it is, leaving your input unchanged.
Is my URL sent to a server?
No. Encoding and decoding happen entirely in your browser using the native JavaScript functions, with no API call, no upload and nothing stored. That is deliberate: URLs routinely carry session tokens, signed links, password-reset addresses and internal hostnames, so pasting one into a third-party service means handing that service a credential. Here the text moves from the input box into a local function and back onto the screen. It also means the tool works offline and responds instantly, with no length limit beyond your device’s memory.