URL decode and encode
Three different things are called URL encoding, and they disagree about the plus sign. This one asks which you mean — and says when your string was encoded twice.
Runs in your browser0 bytes uploadedThree different things are called URL encoding, and they disagree about the plus sign. This one asks which you mean — and says when your string was encoded twice.
Runs in your browser0 bytes uploadedA single value out of a URL. "+" stays a plus sign.
Nothing at the counter yet.
A URL is allowed to contain a surprisingly small alphabet. Letters, digits, and a handful of punctuation marks are safe; everything else — spaces, accented letters, ampersands that are part of a value rather than a separator, every emoji, every character in every writing system that is not English — has to be smuggled through as its bytes, written out in hexadecimal and introduced by a percent sign. That is percent-encoding, defined in RFC 3986, and decoding is simply the reverse trip: find a percent sign, read the next two characters as a hexadecimal byte, collect the bytes, and interpret them as UTF-8 text.
That last step is the one most tools skip past, and it is where the interesting failures live. %C3%A9 is not two characters. It is one character —é — spread across two bytes, and decoding the halves separately produces garbage. A four-byte emoji is four percent sequences that mean one glyph. Because UTF-8 has strict rules about which byte patterns are legal, a sequence can be detectably wrong rather than merely ugly, and this tool says which rule was broken instead of handing back a row of replacement characters.
Here is the trap that quietly ruins data every day. There is not one specification called URL encoding. There are three, and they do not agree.
encodeURIComponent escapes everything that could act as a separator, which is what you want for a single value. encodeURI deliberately leaves:, /, ?, #, & and= alone, because it is meant for a whole address rather than a piece of one. And application/x-www-form-urlencoded — the format a browser uses when it submits a form, and therefore the format most query strings are actually in — writes a space as + instead of %20.
So ?q=C++ is a search for the letter C followed by two spaces, while a file path ending in /C++ is a folder genuinely named after the language. Same character, opposite meanings, and a decoder that hard-codes one rule silently corrupts everything governed by the other. A signature parameter is the painful case: base64 contains plus signs, so a signed download link run through a form-rules decoder comes out with spaces where the signature was, and the failure appears later, somewhere else, as a rejected request.
This tool refuses to guess. It counts the plus signs in your input and tells you how many there are, defaults to the reading that leaves them visible rather than the one that silently converts them, and lets you flip between interpretations without retyping. The choice only appears when your string actually contains a plus sign, because a control that cannot change anything is worse than no control.
If your decoded result still has percent sequences in it, nothing went wrong — the string was encoded twice. It happens constantly with redirect parameters: application code encodes a return address, then a framework or a proxy encodes the whole query string again, and %20 becomes %2520 because %25is how a literal percent sign is written.
Plenty of tools loop until nothing is left, which looks helpful and is not. A percent sign can be encoded on purpose, and a decoder that keeps going destroys any string containing one. So this one peels exactly one layer, checks whether another pass would find anything, and tells you before you start reading the output. The second pass is a button you press, not something that happens to you.
decodeURIComponent("100% free") raises an exception. So does any copy that was cut short in the middle of a multi-byte character. Neither input is exotic — one is a discount, the other is what happens when a URL is selected from a wrapped line in a terminal — and because most tools are a thin wrapper around that one function, both produce either an empty box or your original text with no explanation.
Everything here is decoded as far as it can be. A percent sign that is not followed by two hex digits is treated as a literal percent sign and reported as a note rather than an error, since that is almost always what was meant. A genuinely malformed byte sequence is named for what it is — an overlong form, a surrogate half, a character whose bytes ran out — and given its exact position in the string. Anything that cannot be decoded is left precisely as written. Nothing is dropped, and nothing is replaced with a diamond.
Most people who need a decoder are not really asking for one. They are asking what is inside a link — which tracking parameters got appended, where a redirect actually goes, what the campaign name was. So when the input looks like a URL or a query string, it is split into scheme, host, path, parameters and fragment, one row per parameter, each value decoded on its own.
The parameter table deliberately uses form rules while the path above it does not, which means the same plus sign can be shown two different ways in the same address. That is not an inconsistency to smooth over. It is the single most useful thing this tool can teach, and seeing it happen to your own link explains it faster than any paragraph.
It does not validate URLs, follow redirects, or fetch anything. It also does not normalize: new URL() in a browser will lowercase a host, resolve.. segments and re-encode what you gave it, which is exactly wrong when the question is what your string literally contains, so the breakdown is parsed by hand and shows the original.
For building a clean URL in the first place rather than decoding one, theslug generator turns a title into a path segment that never needs percent-encoding at all. If your decoded text still looks wrong, the culprit is often a character you cannot see — a non-breaking space or a zero-width joiner that survived a copy from a document — and the invisible character finder will name it. For tokens rather than links,base64 decode is the sibling tool, and it shares the same view of what an encoding is: a way of writing bytes down, with the question of which characters those bytes represent kept separate and explicit. The background to that question is in what Unicode is andhow UTF-8 differs from ASCII.
Percent-decoding is arithmetic on a string: scan for a marker, read two hex digits, build a byte, group the bytes into characters. There is no dictionary to consult, no model to run, nothing that a remote machine could do faster or better than the tab you already have open. The JavaScript that performs it is the whole product, which is why your text stays in a variable on this page and no request is made while you type.
That property matters more for URLs than for almost anything else people decode. Query strings are where password-reset tokens, signed download links, session identifiers and API keys tend to end up — and a link is usually pasted into a decoder precisely when someone is trying to work out what those parameters contain. If you want to confirm the claim rather than accept it, the page on verifying local processing shows how to watch for yourself.
Because two different specifications are both called URL encoding and they disagree on that one character. In a query string sent by an HTML form — the application/x-www-form-urlencoded rules — a space is written as a plus, so a plus has to mean a space when you read it back. Everywhere else in a URI, RFC 3986 says a space is %20 and a plus is just a plus. The result is that ?q=C++ means the letter C followed by two spaces, while /files/C++ means a folder actually named C++. Tools that hard-code one rule quietly corrupt everything governed by the other, which is why this one keeps the modes separate, tells you how many plus signs are in your string, and lets you flip between readings without retyping anything.
It means the string was encoded twice. %25 is the encoding of the percent character itself, so an already-encoded %20 that goes through an encoder a second time becomes %2520. Decoding once correctly gives you %20 back, which looks like a failure but is exactly right — the tool undid one layer, and one layer remains. Rather than silently looping until nothing is left, which would destroy any string containing a deliberately encoded percent sign, this tool checks whether another pass would decode anything and tells you so, with a button to run that second pass yourself. Double encoding almost always comes from a redirect parameter that was encoded by application code and then again by a framework or a proxy.
It gets decoded as far as it can be, and you are told precisely where the trouble is. The browser built-in throws an exception on input like 100% free or a copy that was cut short mid-character, so most tools show you either an empty box or your original text with no explanation. Here every problem is listed with its character position, the exact text at that spot, and what is wrong with it: a percent sign not followed by two hex digits is treated as a literal percent and called a note rather than an error, while a genuinely broken byte sequence is named for what it is — an overlong form, a surrogate half, or a character whose bytes ran out. Anything that cannot be decoded is left exactly as written, never replaced with a substitution character.
Here, yes, and the reason is worth understanding rather than trusting. Percent-decoding is pure string arithmetic — scan for a percent sign, read two hex digits, turn them into a byte, interpret the bytes as UTF-8. There is no computation in that which a server could do better, so nothing about this tool needs one, and the JavaScript that runs it is the entire product. Your text stays in a variable in this tab. That matters more for URLs than for most things people decode, because query strings are where session identifiers, password-reset tokens, signed download links and API keys tend to live, and a link is usually pasted into a decoder precisely when someone is trying to work out what those parameters contain.