About URL Decode

URL decoding reverses percent-encoding: every %XX sequence becomes the byte it represents, and the resulting UTF-8 bytes become readable text — %E0%B8%AA%E0%B8%A7%E0%B8%B1%E0%B8%AA%E0%B8%94%E0%B8%B5 turns back into สวัสดี. You need it constantly when debugging: reading query strings from access logs, inspecting callback URLs from OAuth flows, understanding what a browser actually sent, or unpacking tracking parameters.

Decoding is where encoding mistakes become visible. Double encoding, mixed charsets, and truncated sequences all fail (or look wrong) at decode time, and each failure mode has a distinct signature described below. Everything runs locally in your browser.

How to use URL Decode

  1. Enter or paste the input in the text area.
  2. Click Convert to encode or decode.
  3. Copy or download the result.

Example

Input

Your input or data here

Output

Result will appear here after running the tool

How decoding works

The decoder scans for % followed by two hex digits and replaces each with the corresponding byte; all other characters pass through. The collected bytes are then interpreted as UTF-8. Two things can go wrong mechanically: a malformed sequence (% not followed by two hex digits) raises a URIError-style failure, and bytes that are not valid UTF-8 render as replacement characters (�).

Note what decoding does not do: it does not parse the URL. If you decode a full query string first and then split on &, values that legitimately contained %26 (&) will now split incorrectly. The correct order is always: parse structure first (split on ?, &, =), then decode each value individually. Every URL library (URLSearchParams, urllib.parse) works this way.

Recognizing encoding pathologies at a glance

  • %2520, %253D — double encoding: % was itself encoded to %25. Decode twice to recover, then fix the producer.
  • â€, ส... — UTF-8 bytes decoded as Latin-1 somewhere upstream (mojibake). The %XX layer is fine; a charset conversion is wrong.
  • + appearing where spaces belong — the value passed through form-encoding; decode + as space only for form contexts.
  • A lone % or %2 at the end — truncated input; the last sequence was cut off by a length limit.
  • %u0E01 style — non-standard legacy escape() output from very old JavaScript; needs unescape(), not standard decoding.

A worked example: reading an OAuth redirect

A typical callback URL looks like https://app.example.com/cb?state=abc%3Ax1&redirect_uri=https%3A%2F%2Fapp.example.com%2Fdone&scope=read%20write. Split at & first, then decode each value: state is abc:x1, redirect_uri is https://app.example.com/done, scope is 'read write'. Decoding before splitting would have broken at any & hidden inside a value. This split-then-decode discipline is the single most useful habit when reading URLs in logs.

Common errors and how to fix them

URIError: malformed URI sequence

Cause: A % not followed by two hex digits — either truncated input or a literal percent sign that was never encoded.

Fix: If the value legitimately contains %, it should have been sent as %25. For truncation, recover the full value from the source.

Decoded text still contains %XX sequences

Cause: Double encoding — the value was encoded twice, so one decode only removes one layer.

Fix: Decode again. Then find and remove the duplicate encoding step in the producing code; double encoding also breaks signature verification and caching.

Output shows � replacement characters

Cause: The decoded bytes are not valid UTF-8 — usually a legacy charset (TIS-620, Windows-1252) was percent-encoded.

Fix: Decode the %XX layer here, then convert the bytes from the legacy charset in a script (e.g. Python: bytes.decode('cp874')).

Spaces appear as + after decoding

Cause: The value came from an HTML form or form-style query string, where + encodes a space — standard percent-decoding leaves + alone.

Fix: Replace + with a space when (and only when) the source is form-encoded data.

Tips and best practices

  • Parse first, decode second: split the URL on structural characters before decoding values, or hidden separators will corrupt the parse.
  • Decoded ≠ safe: never insert decoded values into HTML or SQL without escaping — percent-encoding is transport armor, not sanitization, and attackers rely on people forgetting that.
  • When a signature (OAuth 1.0, AWS SigV4) fails mysteriously, compare the exact encoded strings both sides signed — a %2f vs %2F case difference or a stray double-encode is the usual culprit.
  • Logs often contain encoded values inside encoded values (a URL as a query parameter). Peel one layer at a time and check plausibility after each pass.

Frequently asked questions

Why do I still see %25 or %2520 in my data?
That is double encoding: %25 is the encoding of % itself. Somewhere, an already-encoded value was encoded again. Decode repeatedly until stable, then fix the producing layer — double encoding also breaks caches and signatures.
Should + become a space?
Only in form-encoded contexts (HTML form submissions and query strings parsed by form rules). In RFC 3986 percent-encoding proper, + is a literal plus. Know your source before converting.
The decoded text is garbled non-ASCII — why?
The bytes behind the %XX sequences are not UTF-8. Legacy systems encode Thai as TIS-620/Windows-874 or Western text as Windows-1252. Decode the percent layer, then convert the charset with a script.
Can I paste a whole URL?
You can, but decode values individually after splitting on ? & = — decoding the whole URL first can turn hidden separators inside values into structure and corrupt your parse.
Is decoding safe for untrusted input?
Decoding itself is safe here (it runs in your browser and outputs text). But treat the result as untrusted data: decoded strings frequently carry injection payloads precisely because encoding hid them from naive filters.

Embed this tool

Add URL Decode to your own site, blog post, or internal docs — free, no signup. The widget runs entirely in your visitors' browsers, same as it does here.