Skip to content
FindTool

    URL Decoder

    Decode percent-encoded URLs and break query strings into a readable table.

    URL Decoder tool

    Building a link instead? Use the URL Encoder.

    What this tool does

    It turns %C3%A9 back into é, %2F back into /, and a 400-character analytics URL back into something you can read. Paste a whole address and it also splits out the scheme, host, path and fragment, and lists every query parameter as a row you can actually scan.

    Multi-byte characters are reassembled properly. A single emoji arrives as four separate escapes, and decoding them one at a time produces four pieces of nonsense — so consecutive escapes are collected and decoded together.

    Common uses

    • Reading an OAuth callback or SSO redirect, where the interesting value is a nested URL wrapped in escapes.
    • Working out what a tracking link is actually pointing at before clicking it.
    • Debugging a request where a parameter arrived wrong — seeing the raw and decoded forms side by side usually identifies whether the sender or the receiver is at fault.
    • Pulling a signed URL apart to inspect its expiry and signature parameters.
    • Recovering a filename from a Content-Disposition header.

    A short example

    This value:

    next=https%3A%2F%2Fapp.example.com%2Fbilling%3Fplan%3Dpro

    decodes to:

    next=https://app.example.com/billing?plan=pro

    Note that the inner ? was encoded. Had it not been, the outer URL would have treated plan=pro as one of its own parameters.

    Double encoding, and how to recognise it

    If decoding leaves %3A still visible in the output, the value was encoded twice. The giveaway is %25 in the input: that is an encoded percent sign, which means the escapes after it are themselves escaped. Turning on repeated decoding unwinds the whole chain and reports how many passes it took.

    This matters beyond tidiness. A proxy or gateway that decodes once while the application decodes twice is the basis of several path-traversal bypasses — %252e%252e%252f passes a filter looking for ../ and becomes it a layer later.

    Worth knowing

    A decode can legitimately fail. %ZZ is not an escape, and %E9 alone is a Latin-1 byte from the old escape() function, not valid UTF-8. Rather than silently producing replacement characters, this tool names the position that failed and explains what the sequence probably was.

    One caution about the parameter table: duplicate keys are kept, because they are meaningful. ?tag=a&tag=b is two values, and frameworks disagree about whether that means a list, the first value, or the last one.

    Frequently asked questions

    Why does a plus sign sometimes become a space and sometimes not?

    It depends which decoder runs. decodeURIComponent("a+b") hands back a+b untouched, while a form decoder — URLSearchParams, PHP’s $_GET, most framework query parsers — returns a b, because a plus means a space in application/x-www-form-urlencoded. That is what quietly destroys Base64 signatures passed in query strings, where the plus was literal and should have been sent as %2B.

    Should I decode a query string before or after splitting it?

    After, always. Split on &, then on the first =, and decode each name and value only at the end. Decode first and an escaped %26 inside a value becomes a real separator, so note=a%26b=c turns into two parameters and part of the text vanishes. That ordering mistake is the basis of most parameter-smuggling reports.

    Where does everything after the hash go?

    Nowhere — a fragment is never transmitted. RFC 3986 §3.5 makes it purely client-side, so the server, the access log and any WAF in between see the URL up to but not including the #. That is why OAuth implicit-flow tokens placed in a fragment stay out of server logs, and why a redirect target hidden after a hash cannot be validated on the server.