URL Encoder/Decoder

Encode or decode URL components (escape special characters).

Percent-encoding: the rules, the three encoders, and the bugs they cause

A URL may only contain a small set of ASCII characters, so anything else has to travel as percent-encoded bytes: %XX where XX is the byte in hexadecimal. RFC 3986 splits the allowed characters into an unreserved set that never needs encoding (letters, digits, -, ., _, ~) and a reserved set that has structural meaning: : / ? # [ ] @ delimit the parts of a URL, and ! $ & ' ( ) * + , ; = delimit values inside a part. A reserved character used as data, such as an & inside a search term, must be encoded or it will be read as a delimiter. Non-ASCII text is encoded as its UTF-8 bytes, so a single Devanagari letter becomes three %XX groups. Uppercase hex is the recommended form, and decoders accept either case.

What this tool does

Encode mode runs JavaScript's encodeURIComponent(), which leaves only letters, digits and - _ . ! ~ * ' ( ) untouched and encodes everything else, including spaces (%20), slashes (%2F), question marks, ampersands and equals signs. That makes it the right function for a single query-string value or path segment, and the wrong one for a whole URL: paste https://example.com/a?b=c and you get https%3A%2F%2Fexample.com%2Fa%3Fb%3Dc, which is exactly what you want when the URL is itself a parameter (a redirect_uri, for example) and exactly what you do not want otherwise. Decode mode runs decodeURIComponent() and shows "Error: Malformed URL sequence" when the input has a lone %, a % followed by non-hex characters, or bytes that do not form valid UTF-8. A plus sign is left as a plus sign in both directions; see below for why. The swap button moves the output back into the input so you can round-trip a value.

Three encoders that look the same and are not

FunctionLeaves unencodedSpace becomesUse it for
encodeURIComponent (this tool)A-Z a-z 0-9 - _ . ! ~ * ' ( )%20One query value or one path segment
encodeURIEverything above plus ; , / ? : @ & = + $ #%20A complete URL that is already correctly structured
URLSearchParams, HTML formsA-Z a-z 0-9 * - . _+application/x-www-form-urlencoded bodies and query strings built by the browser

The plus sign is the classic bug. In form encoding a space is sent as +, and a real plus sign as %2B. Servers therefore turn + into a space when reading form data and query strings, but not when reading a path. decodeURIComponentnever converts +, so a value that arrives as hello+world decodes to hello+world in this tool; replace the plus signs with %20 first if the data came from a form. Note also that URLSearchParams encodes ~ and !'()* differently from encodeURIComponent, so two correct encoders can produce different strings for the same value. Both decode to the same thing.

Gotchas that reach production

  • Double encoding. Encoding an already-encoded value turns %20 into %2520. The server decodes once and hands your code a literal %20. Encode exactly once, at the point where the value goes into the URL.
  • Decoding twice. The mirror bug: a value that legitimately contains %25 becomes corrupted if a framework decodes it and your code decodes it again. Decode once, at the boundary.
  • Encoded slashes in paths. Apache rejects %2F in a path by default (AllowEncodedSlashes) and Tomcat needs an explicit flag, so an ID that contains a slash is safer in a query parameter than in the path.
  • The fragment never reaches the server. Anything after # stays in the browser. If a value can contain #, encode it as %23.
  • Hostnames are different. Non-ASCII domain names are not percent-encoded; they use Punycode (IDNA), which is why an international domain appears as an xn-- label in DNS.
  • Length. No RFC caps URL length, but browsers, CDNs and servers do; a common server default is 8 KB for the request line and older browsers stopped at about 2,000 characters. Long payloads belong in a POST body.

Command-line equivalents

python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=''))" 'a b&c'
python3 -c "import urllib.parse,sys; print(urllib.parse.unquote(sys.argv[1]))" 'a%20b%26c'
node -p "encodeURIComponent(process.argv[1])" 'a b&c'
jq -rn '"a b&c" | @uri'
curl -G --data-urlencode 'q=hello world' https://example.com/search   # curl encodes for you
[uri]::EscapeDataString('a b&c')        # PowerShell; UnescapeDataString to reverse

Security: decoded data is still untrusted

Percent-encoding is a transport convention, not a security control. Every server decodes the URL before your handler sees it, so an encoded payload is exactly as dangerous as a raw one. %2e%2e%2f is ../ and can walk out of a directory if paths are built from user input; %0d%0a is a line break and can forge lines in a log or a header; an encoded @ in a redirect target can point a request at a different host. Decode once, validate the decoded value against an allow-list, and never build SQL or shell commands from it (the SQL injection guide covers the parameterised alternative).

Runs in the page

Encoding and decoding use the browser's built-in functions and nothing is transmitted. Pair this tool with the Base64 encoder when a binary value has to ride inside a URL: Base64 first, then percent-encode the +, /and = characters, or use the URL-safe Base64 alphabet and skip that step.

How to use

  1. Choose Encode to percent-encode a value, or Decode to turn %XX sequences back into text.
  2. Paste one value at a time: a query parameter value, a path segment, or a URL that will itself become a parameter. The output updates as you type.
  3. To build a full URL, encode each parameter value separately and join them with ? & and = yourself; do not paste the whole URL into Encode.
  4. If Decode reports a malformed sequence, look for a lone % sign or a value that was already decoded once.
  5. Use the swap button to move the output back into the input and round-trip it, and Copy to take the result.

Common use cases

  • Putting a search term with spaces, ampersands or Hindi text into a query string without breaking the URL.
  • Encoding a redirect_uri or state value for an OAuth 2.0 authorisation request.
  • Decoding percent-encoded paths and query strings copied from server access logs or browser history.
  • Checking whether a value was double-encoded (%2520) before it reached your API.
  • Escaping a JSON blob or a file path so it survives as a single parameter.
  • Preparing test inputs for a web application firewall or an input-validation review.

Frequently asked questions

What is the difference between encodeURI and encodeURIComponent?

encodeURI keeps the characters that give a URL its structure (slash, colon, question mark, ampersand, equals, hash) so it can be applied to a complete URL. encodeURIComponent encodes those too, which is correct for a single value that will be placed inside a URL. This tool uses encodeURIComponent.

Why is a space sometimes "+" and sometimes "%20"?

HTML forms and URLSearchParams use the application/x-www-form-urlencoded format, where a space is sent as a plus sign and a literal plus as %2B. RFC 3986 percent-encoding, used for paths and by encodeURIComponent, writes a space as %20. Servers convert + to a space only in query strings and form bodies, never in paths.

Why does Decode show "Malformed URL sequence"?

The input contains a percent sign that is not followed by two hexadecimal digits, or the decoded bytes are not valid UTF-8. A stray % in a literal value must itself be written as %25. If the text was already decoded once, decoding again can also fail.

Can I paste a whole URL into Encode?

Only if the whole URL is going to become a parameter value, such as a redirect_uri. The tool encodes the scheme, slashes and question mark too, so the result is no longer a working address. To fix up an entire URL, encode each parameter value on its own and assemble the URL yourself.

Does it handle emoji, Devanagari and other non-ASCII text?

Yes. Characters outside ASCII are encoded as their UTF-8 bytes, one %XX group per byte, so an emoji becomes four groups and most Indian-script letters three. Decoding reassembles the bytes into the original characters.

Is URL encoding a way to hide or protect data?

No. It is reversible by design and every server decodes it automatically, so an encoded attack payload is as dangerous as a plain one. Treat decoded parameters as untrusted input and validate them; use TLS for confidentiality and signing or encryption for integrity.

Why do two tools give different encodings of the same value?

Because there are several correct encoders with slightly different reserved sets. encodeURIComponent leaves ! * ' ( ) and ~ alone, URLSearchParams encodes them and writes spaces as +, and strict RFC 3986 encoders encode ! * ' ( ) as well. All of them decode to the same original text.

Advertisement