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
| Function | Leaves unencoded | Space becomes | Use it for |
|---|---|---|---|
encodeURIComponent (this tool) | A-Z a-z 0-9 - _ . ! ~ * ' ( ) | %20 | One query value or one path segment |
encodeURI | Everything above plus ; , / ? : @ & = + $ # | %20 | A complete URL that is already correctly structured |
URLSearchParams, HTML forms | A-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
%20into%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
%25becomes corrupted if a framework decodes it and your code decodes it again. Decode once, at the boundary. - Encoded slashes in paths. Apache rejects
%2Fin 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 reverseSecurity: 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
- Choose Encode to percent-encode a value, or Decode to turn %XX sequences back into text.
- 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.
- To build a full URL, encode each parameter value separately and join them with ? & and = yourself; do not paste the whole URL into Encode.
- If Decode reports a malformed sequence, look for a lone % sign or a value that was already decoded once.
- 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?
Why is a space sometimes "+" and sometimes "%20"?
Why does Decode show "Malformed URL sequence"?
Can I paste a whole URL into Encode?
Does it handle emoji, Devanagari and other non-ASCII text?
Is URL encoding a way to hide or protect data?
Why do two tools give different encodings of the same value?
Advertisement