URL Encoder and Decoder

Paste a %-encoded string or the text behind it and convert either way. Paste as you go — there is no button. The + question and the strict RFC 3986 character set are both switches, because guessing either one silently produces the wrong string.

Paste anything — a full URL, a query string, encoded text, or raw text to encode.

URL options — only change how

Form encoding writes a space as +, which is not the same as %20 — so it has its own switch below.

RFC 3986 encodes five characters that encodeURIComponent leaves alone — needed when a URL goes inside another URL or into a signature.

On for application/x-www-form-urlencoded input (forms, query strings). Off when + is real data.

When you need this

  • A query parameter arrives double-encoded and you need to see what it actually says.
  • You are building a signature or a redirect URL and the + versus %20 difference decides whether it validates.
  • A log line shows a percent-encoded payload and you want the readable form without writing a one-off script.

Why other URL encoders fail here

Most tools decode with decodeURIComponent and stop there, so + stays a literal plus. That is correct for a path and wrong for a query string, and the tool never asks which one you have.

Almost none offer the strict RFC 3986 set. encodeURIComponent leaves !'()* unescaped for historical reasons, which breaks signatures and nested URLs.

When a % is malformed they say URI malformed and nothing else — no position, no character, no hint that the string may have been truncated mid-escape.

Encoding an already-encoded value is allowed silently, so % becomes %25 and the result is wrong in a way that looks plausible.

Frequently asked questions

Should I use + or %20 for a space?

It depends on where the string is going, which is why it is a switch rather than a default. In the query part of application/x-www-form-urlencoded data — HTML form submissions, and most server frameworks' query parsers — a space is written as +, so decoding must turn + back into a space. In a path segment, a fragment or a value you produced with encodeURIComponent, a space is %20 and a + is a literal plus. Turning the switch on when you should not have will silently replace real plus signs with spaces.

What does the strict character set change?

Exactly five characters: !, ', (, ) and *. Standard encodeURIComponent leaves them as-is, because early web code relied on that. RFC 3986 reserves them, so a URL that will be nested inside another URL, or fed into a signature or an HMAC, must have them percent-encoded. If you are producing a signature that the other side rejects while the decoded value looks identical, this is the usual reason.

Why does the result still contain percent signs?

That means the value was encoded more than once, which is common when a parameter is encoded and then the whole URL is encoded again. The tool reports how many %XX sequences remain in the output so you know a second pass is needed. Decoding again reaches the original text, but do check the result: decoding twice will also decode any % that was meant to be a literal percent sign.

It says my % is malformed. What counts as valid?

A percent sign must be followed by exactly two hexadecimal digits. %20, %E4 and %2f are valid; %, %2 and %ZZ are not. The tool tells you the position of the first bad escape and how many there are, because this is nearly always truncation or a hand-edited string rather than something subtle — a value cut short mid-escape loses the second hex digit.

The escapes look fine but it still fails with invalid UTF-8.

Percent-encoding operates on bytes, and the tool requires those bytes to be valid UTF-8. %E4%F8 fails because F8 cannot begin a UTF-8 sequence. In practice this means the text was encoded in a legacy single-byte or double-byte character set such as Latin-1 or GBK before being escaped. The panel shows the offending bytes in hex so you can tell which encoding produced them.

Is my input sent anywhere?

No. The conversion runs in this page with plain string operations, and there is no backend to send it to. Open the DevTools Network panel and convert something: no request is made. The site installs as a PWA, so once the page has loaded it keeps working with the network disconnected.

Other tools