URL Decoder
Convert percent-encoded URLs and query strings into readable text for debugging and logs.
Paste a percent-encoded URL or query parameter and read what it actually contains. Decoding is the easy half of percent-encoding — the hard part is recognising when a value has been encoded twice, when a plus sign means a space, and when decoding early opens a security hole. This page covers the failure modes worth knowing.
Spotting a double-encoded value
The single most common reason a decoded URL still looks wrong is that it was encoded twice. Percent-encoding escapes the % character itself as %25, so a value that passes through two encoding layers accumulates a prefix: a space starts as %20, and encoding that again produces %2520.
If your output still contains %20, %26, or %3D after one decode pass, you are looking at a double-encoded string and need a second pass. The tell is any %25 sequence followed by two more hex digits.
This usually means two layers of your stack both decided to encode: a client library that encodes query parameters, sitting behind a reverse proxy or CDN that encodes them again, or an application that encodes a value before handing it to a router that does the same. Fix the duplicate encoder rather than decoding twice in production — a value containing a genuine literal % will decode into garbage under a blind second pass.
Why a plus sign sometimes means space
+ means space in application/x-www-form-urlencoded data, which is what HTML forms produce and what most query strings use in practice. It does not mean space anywhere else in a URL. In a path segment, + is a literal plus character.
This matters because JavaScript's decodeURIComponent follows the URI spec, not the form spec: it leaves + completely alone. Decoding q=hello+world with it yields hello+world, not hello world. URLSearchParams does apply form rules and gives you the space.
So before you trust a decoded result, ask which layer produced the string. A query string from a form needs form decoding; a path segment or a value from an API needs plain percent-decoding. Guessing wrong silently corrupts any value containing a real plus — version numbers, base64 payloads, and phone numbers in E.164 format are the usual casualties.
Decode the parts, not the whole URL
Decoding an entire URL in one shot destroys the information that tells you where one parameter ends and the next begins. Consider ?note=a%26b=2. That is a single parameter named note whose value is the literal string a&b=2. Decode the whole URL and you get ?note=a&b=2, which now reads as two parameters. The delimiter and the data have become indistinguishable.
The correct order is always: split on the structural delimiters first (?, &, =, /), then decode each piece individually. Encoded delimiters inside a value are precisely what encoding exists to protect, and whole-string decoding throws that protection away.
If you are debugging a URL with nested structure, the URL parser splits it into components before decoding each one, which avoids this class of mistake entirely.
Never validate before you decode
Decoding order is a security property, not a style preference. A filter that checks for ../ and then decodes its input is trivially bypassed by %2e%2e%2f, which passes the check as an innocuous string and becomes ../ immediately afterwards. The same trick defeats naive SSRF blocklists, extension checks, and allowlists of permitted paths.
Decode fully first, confirm the result is stable — decoding again should change nothing — and only then validate. If a second decode pass alters the string, treat the input as hostile rather than decoding in a loop; repeated decoding until the value stops changing is itself a denial-of-service vector and can normalise an attacker's payload into exactly the form they wanted.
Malformed input and what it means
A percent sign must be followed by exactly two hexadecimal digits. Anything else is invalid, and strict decoders reject it: in JavaScript, decodeURIComponent("100%") throws a URIError rather than returning the string unchanged. Unescaped percent signs in user-supplied text are the usual source, and a surprising number of production errors trace back to a price or discount field.
The other failure is invalid UTF-8. Multi-byte characters encode to multiple percent sequences — é is %C3%A9, not %E9 — so a truncated or Latin-1-encoded string produces byte sequences that are not valid UTF-8. A bare %E9 from a legacy system will throw or come back as a replacement character. Seeing é where you expected é means the bytes were decoded as Latin-1 somewhere upstream and re-encoded as UTF-8.
Related tools
Try these tools that work well with this one
URL Encoder
Free online URL encoder tool for encoding special characters
URL Builder
Free online URL builder tool for constructing URLs with parameters
URL Parser
Free URL parser tool that breaks down URLs into their components
URL Redirect Checker
Trace HTTP redirects, status codes, and headers
URL Validator
Free online URL validator tool to check URL validity
Base64 Decoder
Convert Base64 back to original text and files
Related guides
Tutorials and guides to get more from this tool
URL Encoding & Decoding: Definitive Guide
Fix broken URLs instantly! Master URL encoding/decoding to prevent data loss and API failures. Complete guide with examples for 2025.
URL Validation: Why Regular Expressions Aren't Enough
Validating URLs is harder than it looks. Explore why simple regex fails and how to ensure URLs are properly formatted and safe.
The Art of URL Building: Best Practices for 2025
Master the construction of complex URLs. Learn about protocol relative URLs, proper parameter encoding, and avoiding common pitfalls.
ThenCatch is a free developer toolkit. Learn more about us.