URL Decoder

Paste a percent-encoded URL or query string and get the readable text back, plus every key and value broken out into a table.

Files never leave your device

Component escapes the most characters, for a single value. Full URI leaves URL punctuation like / and ? alone. Form also turns spaces into +.

Percent-encoding hides in three places: a whole URL, a single value, and a query string built from several of them. This page reads all three back into text — pasted by hand, byte for byte — and splits a query into its key/value pairs so you don't have to trace the &s yourself.

Reading one escape by hand

A percent triplet is one byte written in hex: %20 is the byte 0x20, which is a space. %2B is 0x2B, a literal plus. Multi-byte characters take more than one triplet — %E1%BA%BF is three bytes, 0xE1 0xBA 0xBF, which together form one UTF-8 character, ế. Put a run of these next to plain ASCII and Ti%E1%BA%BFng%20Vi%E1%BB%87t decodes to Tiếng Việt: the ASCII letters pass through untouched, the accented ones each cost three triplets, and the one %20 becomes the space between the two words.

Choosing Component, Full URI, or Form mode

The three modes decode a different amount of the input, and picking the wrong one either leaves escapes untouched or corrupts structure that was never meant to move. Component unescapes every percent-encoded character it recognizes, which is right for a single value pulled out on its own — a query parameter, a path segment, a cookie. Full URI is for a whole address pasted as one piece: it deliberately leaves the escaped forms of / ? # & = + $ , : ; @ alone, so a slash that was legitimately percent-encoded inside a filename (%2F) doesn't unescape into a literal / and get misread as a new path segment. Form behaves like Component but also reads a + as a space, matching how a browser encodes an HTML form submission — use it for anything that came out of an application/x-www-form-urlencoded body or a query string, since a literal + has no other way to survive that round trip.

Two ways a decode can fail

100% fails at the very last character — nothing follows the %, so there's no second hex digit to read. 50%2 off fails one character earlier, at the %, because %2 is followed by a space rather than a hex digit. Both are reported as an invalid percent-encoded sequence, at the exact index of the offending %.

A different kind of failure happens when every escape is syntactically fine but the bytes they spell don't add up to valid text. %E1 alone decodes as a well-formed single-byte escape, but 0xE1 is the first byte of a three-byte UTF-8 character with no continuation bytes following it — there is no text there to produce. %FF%FE is the same problem with two bytes that never start valid UTF-8 at all. Both report as not valid UTF-8, a message that means "these bytes were never text," not "you made a typo."

Tip: Position 0 in a bad-escape error always counts from the start of exactly what you pasted — if you pasted a whole URL, count from the very first character, not from the start of the query string.

Pulling a query string apart

Paste https://example.com/search?q=hello+world&lang=vi#frag and the table below shows two rows: qhello world, langvi. The path before the ? and the #frag after it are both set aside — neither is part of the query — and the + in hello+world decodes to a space, because a query string follows form rules.

A query string also has more than one valid spelling: a space can be written as + or %20, and a literal . decodes the same whether or not it was ever escaped as %2E — so writing one back out from its decoded pieces can look different from what you pasted, character for character, while meaning exactly the same thing.

Frequently asked questions

What does "invalid percent-encoded sequence" mean?
It means a % in your text is not followed by two valid hex digits — the escape itself is malformed. `100%` fails this way because nothing follows the %; `50%2 off` fails because %2 is followed by a space instead of a second hex digit. The error names the exact character position of the broken %, so you can go straight to it rather than scanning the whole string.
What does "not valid UTF-8" mean, and how is it different from a bad escape?
This is a decode that looks fine at the syntax level — every % is followed by two real hex digits — but the bytes those triplets spell out don't form valid UTF-8 text. `%E1` alone is this case: a lone byte that starts a three-byte UTF-8 sequence but has no continuation bytes after it, so there is no character to decode it into. A bad escape is a typo in the encoding; bad UTF-8 is bytes that were never text to begin with.
Why did my plus signs turn into spaces?
Only when the text looks like a query string or you're in form mode — + means a literal space there, the same convention an HTML form uses when it submits. In component or full URI mode a + decodes to a literal +, because that convention only applies to form-urlencoded data.
What happens if the same key appears twice, like `a=1&a=2`?
Both rows show up. The parser doesn't merge or de-duplicate keys — a query string is allowed to repeat one, the way a set of checkboxes or a multi-select does — so every pair appears exactly as it was pasted, in the order it appeared.
Why does pasting a whole URL only show me the query part?
Because the query is usually what you're trying to read. Paste a full address and everything before the ? and after a # is set aside — the path and the fragment are not part of the query and would otherwise corrupt the last value if they leaked in. Paste a bare query string with no ? at all and it's read directly, no address required.
Is the text I paste here uploaded anywhere?
No. Decoding runs in JavaScript inside your browser tab the instant you type or paste, and no request carries your text off the device. That matters when what you're decoding is a session token, an internal link, or a query string you'd rather not hand to a server just to read it.
Why is there no unified "invalid input" error for both problems?
Because they point you at two different fixes. A bad escape means go find the % and fix the digits after it — the position tells you exactly where. Bad UTF-8 means the bytes underneath are not text at all, which usually means you pasted something that was never meant to be percent-decoded, like raw binary that happened to contain a % character.