URL Encoder
Percent-encode a single value, a query string or a whole URL, without encoding it twice, and decode escapes back to text with the position of anything that is wrong.
Overview
A URL may only contain a small set of ASCII characters, and some of them have a meaning: /
separates path segments, ? starts the query, & separates its pairs,
# starts the fragment. Percent-encoding, defined in RFC 3986, writes every other character, and
every character that should lose its meaning, as % followed by the two hex digits of each of its
UTF-8 bytes. A space becomes %20, & becomes %26, ü
becomes %C3%BC.
RFC 3986 calls A to Z, a to z, 0 to
9 and - . _ ~ unreserved: they never need encoding. The reserved characters
: / ? # [ ] @ ! $ & ' ( ) * + , ; = are left alone where they have their meaning and encoded
where they are data. Which of the two applies depends on where a character stands, which is why the tool has
three encoding modes.
Web interface
Paste a URL, text or an encoded string into the input; the output updates as you type.
Auto works out the direction by itself, Encode and Decode
fix it. When encoding, Encoding chooses Component, Query String or Full URL. When decoding,
Plus sign chooses whether a + stays as it is or stands for a space. Each row is
only shown when it applies.
The line under the output gives the length before and after, counted in characters as a reader counts them, so an emoji is one. Copy copies the output. Clear empties everything and returns to Auto, Component and Keep. Ctrl/⌘ + Enter runs the conversion again.
How Auto decides
Auto decodes input that contains at least one %XX escape and no % that starts no
escape. Everything else is encoded.
| Input | Auto | Output |
|---|---|---|
caf%C3%A9 | decodes | café |
hello world | encodes | hello%20world |
100% sure %20 | encodes, because % s is no escape | 100%25%20sure%20%2520 |
%E9 | decodes, and reports that the byte is not UTF-8 | none |
Input with escapes that are not UTF-8 is decoded rather than encoded, so the error says what is wrong instead of the input being encoded a second time. When Auto guesses wrong, Encode and Decode settle it.
Encoding modes
The same input, https://example.com/a b?q=ü&next=/x?y=1#top, in each mode:
| Mode | Output |
|---|---|
| Component | https%3A%2F%2Fexample.com%2Fa%20b%3Fq%3D%C3%BC%26next%3D%2Fx%3Fy%3D1%23top |
| Query String | https://example.com/a%20b?q=%C3%BC&next=%2Fx%3Fy%3D1#top |
| Full URL | https://example.com/a%20b?q=%C3%BC&next=/x?y=1#top |
Component is for a single value, such as one query parameter or one path segment. It
encodes everything except A-Z a-z 0-9 - _ . ~ ! * ' ( ), including %, so text that
is already encoded is encoded again. That is what a value needs that really contains %20. It is
what JavaScript's encodeURIComponent does.
Query String is for key=value pairs. The part before the first ? is encoded as
in Full URL. The rest is split at every &, and each pair at its first =; key and
value are then encoded like Component, except that existing %XX escapes stay. A second
? or = is part of the value and is encoded, nothing is dropped. A #
starts the fragment, which is kept. Input without a ? is taken as a query string itself, unless it
starts with a scheme such as https:// or with /; then it is a URL without a query and
is encoded as in Full URL.
Full URL is for a whole address. It encodes only what may not appear in a URL: spaces,
non-ASCII characters, control characters, " < > \ ^ ` { | }, and a % that
starts no escape. Reserved characters and existing %XX escapes stay, so an encoded URL comes back
unchanged and [ ] around an IPv6 address survive.
All three modes write a space as %20, never as +, and Query String encodes a
literal + as %2B, so the result means the same to a form-data decoder and to
everything else.
Decoding
Decoding turns each run of %XX escapes back into bytes and reads them as UTF-8. Hex digits may
be upper or lower case. Everything that is not an escape stays as it is.
A + means a space only in form data, the application/x-www-form-urlencoded format
of HTML forms. Anywhere else in a URL it is a plus sign. Plus sign: Keep, the default, leaves
it alone; As space turns it into a space. %2B becomes + in both
cases.
Decoding runs once. Input that was encoded twice, %2520, decodes to %20; paste the
output back in to decode the second layer.
Errors
Input that cannot be decoded is not decoded half-way. The output stays empty and the line under it says where the problem is, counted in characters from 1:
| Message | Meaning |
|---|---|
the % at position 4 is not followed by two hex digits | A % that starts no escape, such as a percent sign in text or an escape cut off at the end. |
the escapes at position 1 (%E9) are not valid UTF-8 | The bytes are not UTF-8. Usually the text was encoded as Latin-1 or Windows-1252, where é is %E9 instead of %C3%A9. |
the text contains a lone surrogate | When encoding: the input holds half of a character, such as half of an emoji left by a broken copy. It has no UTF-8 form. |
No API
There is no API for this tool. Encoding and decoding run in the browser; in a script, use the function
of the language at hand, such as encodeURIComponent in JavaScript,
urllib.parse.quote in Python or rawurlencode in PHP.
Limits
The input has no length limit. The output is recalculated on every keystroke, which stays unnoticeable up to about a megabyte: 1 MB took under a second in every browser tested, drawing included.
Converting itself is fast: 10 MB take under one second in every browser tested. Drawing that much text in the input and output fields is what takes time, and it depends on the browser. For 10 MB it took 1.5 to 2.5 seconds in Chrome and Firefox and up to about 19 seconds in Safari's engine.
Privacy
Nothing leaves the browser. The conversion runs on the page, the input is not put into the page address, nothing is stored, and Copy writes to the clipboard only when you press it.