Skip to content
LocalOnly

URL Decoder

Stable

Decode percent-encoded URL strings back to plain, readable text.

Everything is processed locally in your browser

About URL Decoder

Turn a percent-encoded URL or query value back into human-readable text. The decoder resolves %XX escapes as UTF-8, so international characters and emoji reappear correctly, and it optionally treats + as a space for form-encoded input. Everything runs in your browser with clear errors for malformed sequences.

Features

  • Decode %XX escapes back to their original characters as UTF-8
  • Optional 'treat + as space' mode for form-encoded query strings
  • Handles emoji and multi-byte international text correctly
  • Clear inline errors for malformed or incomplete escape sequences
  • Live decoding as you type, with one-click copy of the result
  • Works on a single value or a full encoded URL

How to use URL Decoder

  1. 1

    Paste the encoded string

    Drop in a percent-encoded value or a full URL containing %XX sequences from a browser bar, log, or API response.

  2. 2

    Toggle + handling if needed

    If the input came from a form or query string, enable 'treat + as space' so form-encoded spaces decode correctly.

  3. 3

    Copy the decoded text

    The readable text appears instantly. Copy it to reuse elsewhere, or to confirm what a URL actually contained.

Examples

Decode an encoded URL

Percent escapes resolved back to the original characters.

Input

https%3A%2F%2Fexample.com%2Fpath%3Fname%3DJohn%20Doe

Output

https://example.com/path?name=John Doe

How percent-decoding works

Making an encoded URL readable again

Encoded URLs turn up constantly in places you need to read them: analytics reports, referrer headers, OAuth redirect parameters, server logs, error messages. A redirect URI nested inside another URL's query string gets encoded, and if it contains its own query string that gets encoded again, producing a long unreadable run of `%3A%2F%2F` and `%3D`.

Decoding reverses the transformation - each `%XX` triplet becomes the byte it names, and consecutive triplets forming a UTF-8 sequence become the character they encode. What you get back is the original value, which is usually immediately obvious once readable.

Nested URLs are the common case worth expecting. An OAuth `redirect_uri` parameter holds a whole URL, and its own parameters were encoded before being placed there. That means one decode reveals a URL that itself still contains encoded parts, and you decode again to read those. Each layer of nesting is one more pass.

Knowing how many times to decode

Decoding is not automatically safe to repeat. Each pass consumes one layer, and running one pass too many corrupts data - a literal `%25` in the original becomes a bare `%`, and a `%2520` that should decode to the text `%20` becomes a space instead.

The signal to stop is that the result contains no more `%XX` sequences that you expect to be encoded. If you see `%25` in the input, that is a strong indication of double encoding and two passes are appropriate. If the first decode yields clean readable text, stop there.

Where this genuinely matters is when a value legitimately contains a percent sign - a discount code like `SAVE20%`, or a SQL `LIKE` pattern. Over-decoding those produces text that looks fine but has lost a character, which is the kind of bug that surfaces much later.

The plus-sign decision, and malformed input

A decoder has to decide what `+` means, and it cannot know from the string alone. In form-encoded data a `+` is a space; in a URL path it is a literal plus. Guessing wrong mangles email addresses with sub-addressing, turning `user+tag@example.com` into `user tag@example.com`.

The heuristic that works in practice is context: if the value came from a query string or a form submission, treat `+` as a space; if it came from a path segment, treat it as literal. When you control the encoder, using `%20` for spaces and `%2B` for plus signs removes the ambiguity for everyone downstream.

Malformed input is the other case a decoder must handle. A truncated triplet like `%2` at the end of a string, or `%ZZ` where the characters are not hex, is invalid. Strict decoders throw; lenient ones pass the sequence through unchanged. Passing through is usually more useful when you are debugging, since it preserves what you were given rather than losing it to an exception.

Reference

Recognising what you are looking at

PatternMeansAction
%20A spaceDecode once
%2520A double-encoded spaceDecode twice
%25A literal percent signOne layer of double encoding present
%C3%A9The character é in UTF-8Decode as UTF-8
+Space in form data, plus in a pathDepends on context
%3A%2F%2F://A nested URL - expect more layers
%2A truncated tripletInput was cut off

Which tool should you use?

These tasks overlap. Here is how to pick the right one for what you are actually doing.

You are reading a URL from a log or an analytics report
Decode it here. Nested redirect parameters usually need two passes.
The string is dense mixed-case alphanumerics with no % signs
That is Base64, not percent-encoding. Use the Base64 Decode tool.
You are building a URL rather than reading one
The URL Encode tool handles that direction - encode each value separately.
The decoded result is JSON
Pass it to the JSON Formatter to read it comfortably.

Use cases

  • Reading query parameters captured in server or analytics logs
  • Inspecting an OAuth redirect_uri or state parameter
  • Turning an encoded search term back into readable text
  • Debugging why a URL behaves differently than expected
  • Recovering the original value of a form-encoded field

Troubleshooting common errors

The output still contains %20 sequences

Why: The input was double-encoded, so one layer remains.

Fix: Decode again. A `%25` in the original input is the giveaway.

An email address lost its plus sign

Why: `+` was interpreted as a space under form-encoding rules.

Fix: Decode with `+` treated as literal when the value is an email address.

Accented characters appear as é or similar pairs

Why: The decoded bytes were interpreted as Latin-1 rather than UTF-8.

Fix: Decode the byte sequence as UTF-8. The percent-decoding itself was correct.

A percent sign disappeared from a discount code

Why: One decode too many - the `%25` that represented it was consumed.

Fix: Decode only as many times as there are layers. Over-decoding is lossy and easy to miss.

The decoder rejects the input

Why: A malformed triplet - truncated like `%2`, or non-hex like `%ZZ`.

Fix: Check whether the value was truncated in transit. A length-capped log field is the usual cause.

Limitations

What this tool deliberately does not do, so you know when to reach for something else.

  • Whether `+` means a space or a plus cannot be determined from the string alone.
  • Decoding is lossy if applied more times than the input was encoded.
  • Malformed triplets cannot be repaired, only passed through or rejected.
  • The byte sequence must be interpreted with the right text encoding, which the URL does not record.
  • Truncated input cannot be reconstructed.

Frequently asked questions

Learn more

Command Palette

Search for a tool or command