Skip to content
Tools

URL Decoder

Decode percent-encoded URLs, query strings and encoded text instantly into readable format. Everything runs locally in your browser.

DetectedURLPercent-encoded

Encoded

69
Output view
51

In: 69 characters · 1 words · 1 lines · 69 B

Out: 51 characters · 2 words · 1 lines · 51 B

9 decoded · <1 ms

Everything happens locally in your browser. Your data is never uploaded.

What is URL decoding?

URL decoding turns percent escapes back into the characters they stand for. Every %20 becomes a space, every %3F a question mark, and the string becomes readable again. It is the exact reverse of URL encoding, and it is lossless.

The reason any of this exists is that a URL is a single unbroken token made of a restricted set of characters, and it uses a handful of them — /, ?, &, =, # — to mean something structural. A value that contains one of those characters, or a space, or an accent, cannot be dropped in as it stands. So it is escaped: each byte is written as a percent sign and two hexadecimal digits.

Encoded
https%3A%2F%2Finertiapixel.com%2Fsearch%3Fq%3Dweb%20design
Decoded
https://inertiapixel.com/search?q=web design

Notice what that example is: a complete URL that was encoded so it could be carried inside another URL, as a redirect target. That nesting is the single most common reason anyone reaches for a decoder — and the reason it is worth reading a redirect parameter before following it.

How URL decoding works

A decoder walks the string one character at a time. Anything that is not a percent sign is passed through untouched. A percent sign means the next two characters are hexadecimal digits naming a byte, so those three characters are replaced by that one byte.

"%48%69"  →  0x48, 0x69  →  72, 105  →  "Hi"

The part that is easy to get wrong is that escapes describe bytes, not characters. Anything outside ASCII is several bytes in UTF-8, so it arrives as several escapes that have to be reassembled before they mean anything:

One character, several escapes
%C3%A9        →  é     (2 bytes)%E4%B8%AD     →  中     (3 bytes)%F0%9F%8E%89  →  🎉    (4 bytes)

This is why decoding one escape at a time and concatenating the results produces mojibake rather than text, and why a run of four escapes is usually an emoji.

It is also where decoding can fail — and unlike encoding, it genuinely can. Four things go wrong in practice, and this tool names which one it found:

  • A broken escape. A % with fewer than two hex digits after it. Usually a literal percent sign that should have been written %25, or a value cut short by a length limit.
  • Bytes that are not valid UTF-8. Most often text that is really Latin-1, which produces byte sequences UTF-8 has no reading for.
  • A character cut in half. A multi-byte sequence that starts but does not finish, because something truncated the string mid-character.
  • Sequences UTF-8 forbids. Overlong forms, and surrogate halves encoded directly. Both are well-formed in shape and rejected on purpose — overlong forms in particular have been used to slip characters past filters that only checked the short spelling.

Rather than guessing at any of these, the decoder stops and reports the character position, the line and column, the offending escape and a suggested fix. A wrong answer that looks right is worse than no answer.

decodeURI() vs decodeURIComponent()

Both decode percent escapes. They differ on one question: whether the escapes that give a URL its structure should be decoded too.

decodeURIComponent() decodes everything. Use it for a single value you have taken out of a URL — one parameter, one path segment, one redirect target.

decodeURI() refuses to decode eleven of them: : / ? # @ $ & + , ; =. Use it for a complete address you want readable without its shape changing.

Given the same encoded URL, the two give genuinely different answers:

Input
https%3A%2F%2Fexample.com%2Fa%20b%3Fq%3D1
decodeURIComponent — a usable URL
https://example.com/a b?q=1
decodeURI — structure left alone
https%3A%2F%2Fexample.com%2Fa b%3Fq%3D1

The second looks unhelpful in isolation, and in that example it is — the input was an encoded whole URL, so Component was the right choice. But turn it around. If you are decoding a path that legitimately contains an escaped slash, Component destroys it:

A folder name containing a slash
/files/Q1%2FQ2%20report.pdf decodeURI          →  /files/Q1%2FQ2 report.pdf   one filedecodeURIComponent →  /files/Q1/Q2 report.pdf     two path segments

Component silently turned one filename into a directory and a file. Nothing errors — the string is simply now describing something else. That is the failure this distinction exists to prevent.

The rule of thumb: decode a whole URL with decodeURI, and each value inside it with decodeURIComponent. If you are unsure, decode both ways here and compare. When the two agree, the choice did not matter.

Common URL encoded characters

These eight account for the overwhelming majority of escapes you will meet. The tool carries a searchable table of the rest.

EncodedCharacterWhat it means when you see it
%20SpaceThe most common escape there is. A space would end the URL, so it can never appear literally. In form data it may arrive as + instead.
%40@Separates credentials from a host, so inside a value it has to be escaped. This is why encoded email addresses are so common.
%26&Separates one query parameter from the next. Unescaped inside a value, it would split that value into two parameters.
%3F?Starts the query string. A literal question mark in a search term has to be escaped or everything after it is read as parameters.
%3D=Separates a parameter's name from its value. Escaped when the value itself contains one — a Base64 value ending in padding, for instance.
%2F/Separates path segments. The one escape Whole URL mode deliberately leaves alone, because decoding it invents a segment that was not there.
%23#Starts the fragment. Everything after an unescaped # never reaches the server at all, which is why an unescaped one truncates a value silently.
%25%A literal percent sign. It must be escaped because it is what begins every other escape — and seeing %25 in front of what look like escapes means the text was encoded twice.

Two more worth knowing, because they cause more confusion than the rest combined. %2B is a literal plus sign and never becomes a space, however plus signs are being treated — which is what keeps sub-addressed email like first.last+tag@example.com intact. And a bare + means a space only in form data; in a path it is simply a plus.

Common use cases

Decoding is how you find out what a link, a request or a log line actually said.

Query parameters

Reading what a link actually asked for. Search terms, filters and sort orders all arrive escaped, and a parameter is often the fastest way to see why a page returned what it did.

REST APIs

Path segments and query values in a request log are encoded. Decoding one shows the identifier, filter or address that was really sent, rather than the escaped form in the log line.

Redirect URLs

A whole URL nested inside another — ?next=https%3A%2F%2F… — is the classic double-nested case, and the one worth checking before you follow it. Decoding shows where a link actually leads.

Search URLs

Search engines and site search put the query in the URL, escaped. Decoding recovers the exact phrase, punctuation and all, which matters when reproducing a result someone sent you.

Email links

A mailto: link encodes its subject and body, and addresses with a + in them are encoded as %2B. Decoding shows the message a link would compose, and whether the address survived intact.

Form data

An application/x-www-form-urlencoded body is a query string in the request body, with + for spaces. Decoding it turns a captured submission back into the fields somebody filled in.

Web development

Comparing what was sent against what arrived. Most encoding bugs are a value encoded twice or not at all, and both are obvious the moment the string is decoded and read.

Debugging

When a value breaks downstream, decoding it locally says whether the data or the transport is at fault — and if it will not decode, the error names the exact character that stopped it.

URL encoding vs URL decoding

They are exact inverses, and the asymmetry between them is not in the arithmetic. It is in what can go wrong.

Encoding never fails. Every possible piece of text has a percent-encoded form. Hand an encoder anything and it produces valid output.

Decoding can fail, because not every string is validly encoded. That is why a decoder needs error messages an encoder does not, and why this one spends its effort on saying precisely where the input stopped making sense.

The practical differences:

  • Direction of size. Encoding grows text — up to three characters for every byte. Decoding shrinks it back to the original.
  • Certainty. Encoding always succeeds. Decoding validates first, and stops rather than guessing.
  • Where the ambiguity lives. When encoding you know what your text means and are choosing how to spell it. When decoding you are handed a spelling and have to work out what was meant — which is why a decoder needs the mode and plus-sign settings, and an encoder mostly does not.

One thing they share, and it is the thing most worth knowing: neither is encryption. Percent-encoding has no key. Anyone holding an encoded value can read it in seconds — this page will do it for them. An encoded token is exactly as exposed as an unencoded one.

Going the other way? The URL Encoder handles both encoding modes, the plus convention and Unicode.

Best practices

  • Decode values, not whole query strings. Split on & and = first, then decode each piece. Decoding the whole string first makes it readable but no longer safely parseable — a value that contained an encoded & now looks like a separator.
  • Decode exactly once. Each pass strips one layer, so decoding twice out of habit turns a legitimate %2520 into a space that was never meant to be there. If you need two passes, that is a bug upstream worth fixing rather than absorbing.
  • Never validate a decoded string and then use the raw one. Checking a path for ../ before decoding misses %2E%2E%2F entirely. Decode first, then validate what you actually have — this ordering is the root of a whole family of path-traversal bugs.
  • Treat decoded input as untrusted. Decoding is not sanitising. A decoded value is a string someone else chose, and it still needs escaping for wherever it is going next — HTML, SQL, a shell.
  • Assume UTF-8, and prove it if the decode fails. It is what the standard requires and what every modern server produces. Bytes that will not decode are usually Latin-1 from an older system, and have to be decoded as Latin-1 rather than forced.
  • Know which convention produced the string. A query string from an HTML form uses + for spaces; a path never does. Getting this wrong turns plus signs into spaces in exactly the values — email addresses, identifiers — where that does the most damage.
  • Use your platform’s function, not a regular expression. decodeURIComponent and its equivalents handle multi-byte characters and reject malformed input. A hand-rolled replace of %XX does neither, and will quietly corrupt every non-ASCII value it touches.
  • Do not log decoded values carelessly. Decoding often reveals tokens, session identifiers and personal data that were unreadable a moment before — and a value that turns out to be Base64 or a JWT gives up more still, since a Base64 decoder or a JWT decoder reads either without a key. Being encoded was never protecting them, but being decoded makes them trivially greppable.

Frequently asked questions

Is this URL Decoder free?

Yes. Live decoding, both decoding methods, the character reference, search, statistics, copy and download are all free, with no account, no usage cap and no paid tier.

Is my data uploaded?

No. Decoding happens in your browser, in JavaScript running on your own machine. Nothing is sent to a server, stored or logged — you can disconnect from the network after the page loads and it keeps working. That matters here more than it does for most tools, because encoded values are so often tokens, session identifiers and customer data.

What is the difference between decodeURI and decodeURIComponent?

decodeURIComponent decodes every escape. decodeURI deliberately leaves alone the escapes that would change a URL's structure — : / ? # @ $ & + , ; and = — because turning %2F back into a slash inside a path would add a segment that was never there. Use Component for a value you pulled out of a parameter, and Whole URL when you are holding a complete address that only needs its spaces and accents made readable.

Which method should I use?

Component, almost always, because almost always you are decoding one value: a search term, a redirect target, an email address. Whole URL is right when the thing in your hand is a full address and you want it readable without its structure shifting. If you are unsure, decode both ways — if the two agree, the choice did not matter.

Can I decode UTF-8 URLs?

Yes, and it is the default. Percent-encoding describes bytes rather than characters, so a single character often arrives as several escapes: %C3%A9 is é, %E4%B8%AD is 中 and %F0%9F%8E%89 is 🎉. Those are two, three and four bytes respectively, which is why runs of four escapes usually mean an emoji.

Why are spaces encoded as %20?

Because a URL is a single unbroken token — a space would end it, and everything after the space would be read as something else entirely. %20 is the space character's byte value, 32, written in hexadecimal. You will also see + for a space, which comes from HTML form submission rather than from the URL standard, and the Plus signs setting decides which convention this tool follows.

What is the difference between + and %20?

%20 means a space everywhere. + means a space only in application/x-www-form-urlencoded data — form bodies and the query strings forms produce — and means a literal plus sign everywhere else, including in a path. An escaped %2B is always a literal plus, whatever the setting says, which is why sub-addressed email like first.last+tag@example.com survives decoding here but breaks in tools that replace plus signs blindly.

Can I decode query parameters?

Yes, and the tool detects them: paste a query string or a whole URL and it reports how many key=value pairs it found before decoding anything. Decode with Component to read the values. One caution — decoding an entire query string at once makes it readable but no longer safely parseable, because a value that contained an encoded & now looks like a separator. To edit parameters, decode them one value at a time.

Can malformed URLs be decoded?

No, and that is deliberate. A broken escape has no correct interpretation, so guessing would hand you plausible text that is quietly wrong. Instead the tool stops and tells you exactly where the input stopped making sense — the character position, the line and column, the escape it found, and what would fix it. Repair that one spot and the rest decodes.

Why does my URL fail to decode?

Usually one of four things. A stray % that was meant literally and should have been written %25. An escape cut in half by a line wrap or a truncated field. Text that is Latin-1 rather than UTF-8, which produces byte sequences UTF-8 has no meaning for. Or a multi-byte character clipped partway through by a length limit. The error message names which of these it found rather than saying only that something is wrong.

What does double encoded mean?

That the text was encoded twice, so its escapes were themselves escaped: a space became %20, and then the % of %20 became %25, leaving %2520. You will spot it by the %25 sitting in front of what look like escapes. The tool flags it when it sees it. The fix is simply to decode twice — and the real fix is upstream, where something encoded a value that had already been encoded.

Can I decode %uXXXX and \uXXXX escapes?

Yes, with Characters set to Unicode escapes. Neither form is percent-encoding: %u00E9 is the output of JavaScript's old escape() function, which standard decoders reject outright, and \u00e9 is the JavaScript and JSON form. Both encode UTF-16 code units rather than UTF-8 bytes, so characters above U+FFFF appear as a surrogate pair — two escapes that this tool joins back into the one character they spell.

Can I decode long URLs?

Yes. There is no length limit worth mentioning: a query string of several hundred thousand characters decodes in a few milliseconds, and multi-line text with one encoded value per line is fine too. Above roughly 200,000 characters the live decode waits for a pause in typing rather than running on every keystroke.

Is URL decoding the same as decryption?

No, and the difference matters. Encoding has no key and no secret — it is a spelling convention that lets arbitrary text survive being put in a URL, and anyone can reverse it, as this page demonstrates. An encoded token is exactly as exposed as an unencoded one. Treat decoded data with the same care as the original.

Does the decoder work offline?

Once the page has loaded, yes. Decoding, detection, search and the character reference are all local, so you can disconnect and keep working. A connection is only needed to load the page in the first place.

Popular tools

↑ ↓NavigateOpenEscClose