URL Encoder / Decoder
Encodes or decodes a string so that it conforms to the URL specification (RFC 3986 / RFC 1738). All reserved characters are percent-encoded.
%XX sequence.Result
URL Encoding Explained
Why do URLs need to be encoded?
A URL (Uniform Resource Locator) can only be transmitted over the Internet using the US-ASCII character set, and even inside that set a number of characters have a special meaning: ? starts the query string, & separates parameters, = separates a name from its value, # introduces a fragment, / separates path segments, and so on. RFC 3986 (which replaced RFC 1738) therefore defines a small set of unreserved characters that may appear literally anywhere, a set of reserved characters that carry meaning, and a mechanism called percent-encoding for everything else. A URL that contains a space, an accented letter, a Chinese ideogram or a stray ampersand in a parameter value must be encoded before it is sent, otherwise servers and browsers will misinterpret it (or reject it).
How does percent-encoding work?
Each byte that is not allowed is replaced by a percent sign followed by the two hexadecimal digits of the byte value: % + XX. Characters outside US-ASCII are first converted to a sequence of bytes using a character encoding, almost always UTF-8 (as recommended by RFC 3986 and mandated by the WHATWG URL standard). The letter é is C3 A9 in UTF-8 and therefore becomes %C3%A9; in ISO-8859-1 it would be the single byte E9, hence %E9. This is why the character set matters when you decode a URL produced by an old application.
A space is a special case: RFC 3986 encodes it as %20, while HTML forms submitted as application/x-www-form-urlencoded historically replace it by a plus sign +. Because of this, a literal plus sign inside a form value must itself be encoded as %2B.
Reserved and unreserved characters
| Class | Characters | Treatment |
|---|---|---|
| Unreserved | A–Z a–z 0–9 - _ . ~ | Never need to be encoded (encoding them is allowed but pointless). |
| Reserved — general delimiters | : / ? # [ ] @ | Structure the URL. Must be encoded when used as data inside a component. |
| Reserved — sub-delimiters | ! $ & ' ( ) * + , ; = | Have meaning in some components (e.g. & and = in a query). Encode when in doubt. |
| Everything else | space, ", %, <, >, \, ^, `, {, |, }, control characters, non-ASCII | Always percent-encoded. |
Common examples
| Character | Encoded | Character | Encoded |
|---|---|---|---|
| space | %20 (or + in forms) | ; | %3B |
$ | %24 | = | %3D |
& | %26 | ? | %3F |
+ | %2B | @ | %40 |
, | %2C | # | %23 |
: | %3A | / | %2F |
% | %25 | " | %22 |
< / > | %3C / %3E | line break | %0A (or %0D%0A) |
é (UTF-8) | %C3%A9 | € (UTF-8) | %E2%82%AC |
encodeURI vs encodeURIComponent vs form encoding
| Mode | Leaves unencoded | Use it for |
|---|---|---|
URI componentencodeURIComponent() | A–Z a–z 0–9 - _ . ! ~ * ' ( ) | A single value that will be placed inside a URL: a query parameter value, a path segment, a fragment. This is what you want 90% of the time. |
Full URIencodeURI() | Everything above plus ; / ? : @ & = + $ , # | A complete URL that already has its structure (scheme, host, path, query) and only needs spaces and non-ASCII characters escaped. It will not encode an & inside a value, so never use it for parameters. |
Form encodingapplication/x-www-form-urlencoded | A–Z a–z 0–9 - _ . *, space becomes + | Bodies of HTML form submissions (POST) and query strings built by browsers from a <form>. Java's URLEncoder and PHP's urlencode() produce this format. |
| RFC 3986 strict | Only the unreserved set A–Z a–z 0–9 - _ . ~ | OAuth 1.0 signatures, AWS request signing and other protocols that require the strict unreserved set. PHP's rawurlencode() is equivalent. |
encodeURIComponent("a b&c=d/é") // "a%20b%26c%3Dd%2F%C3%A9"
encodeURI("https://x.io/a b?q=é") // "https://x.io/a%20b?q=%C3%A9"
new URLSearchParams({ q: "a b+c" }).toString() // "q=a+b%2Bc" (form encoding)
decodeURIComponent("caf%C3%A9") // "café"
Decoding tip: decodeURIComponent() throws a URIError on malformed input such as a lone % or an invalid UTF-8 sequence. This tool is more forgiving: it decodes every valid %XX pair, keeps invalid ones literally and reports a warning.