Toolkit
All tools
Percent encoding · Free

URL Encoder & Decoder

There is more than one correct percent-encoding, and picking the wrong one is what quietly breaks a query string. See all four at once, decode safely with the fault named and located, and split any link into its scheme, host, path, query, and fragment.

Encoded and parsed in your browser · No link is fetched

34 characters encode to 70 characters with component encoding, over 38 UTF-8 bytes.

Text to encode

Paste the value, not the whole link

Encoding a value is not the same job as encoding a URL, which is why four answers appear below instead of one.

34 of 100,000 characters

Nothing is uploaded, and nothing is fetched.

Four correct answers

The same text, encoded four defensible ways

Component encoding · encodeURIComponent()
Caf%C3%A9%20cr%C3%A8me%20%26%20croissants%20%2F%20%C3%A9t%C3%A9%202026

Use this for one piece of a URL: a single query value, one path segment, a fragment. It escapes the delimiters / ? : @ & = + $ and #, so a value carrying any of them cannot break out of its slot.

Whole URL encoding · encodeURI()
Caf%C3%A9%20cr%C3%A8me%20&%20croissants%20/%20%C3%A9t%C3%A9%202026

Use this on a URL that is already assembled. It leaves the reserved delimiters intact so the structure survives, which is also why it will not protect a value that contains an ampersand.

Differs from component encoding here
Form encoding · application/x-www-form-urlencoded
Caf%C3%A9+cr%C3%A8me+%26+croissants+%2F+%C3%A9t%C3%A9+2026

What an HTML form and URLSearchParams produce. A space becomes a plus sign instead of %20, and that one difference is what silently corrupts data when the two conventions meet.

Differs from component encoding here
RFC 3986 strict · unreserved characters only
Caf%C3%A9%20cr%C3%A8me%20%26%20croissants%20%2F%20%C3%A9t%C3%A9%202026

Only letters, digits and the four marks - . _ ~ survive. Use it for OAuth 1.0 signatures, AWS Signature Version 4, and anywhere a signature has to match byte for byte.

Identical to component encoding here
34 characters in38 UTF-8 bytes70 characters out16 percent escapes
Byte view

Why the encoded string got so much longer

A percent escape carries one byte, not one character. Anything outside ASCII becomes two, three, or four escapes, so an accented word can triple in length and an emoji becomes twelve characters.

Characters
34
UTF-16 units
34
UTF-8 bytes
38
Outside ASCII
4
Character, code point, UTF-8 bytes, and percent-encoded form
CharCode pointUTF-8 bytesEncoded
CU+004343C
aU+006161a
fU+006666f
éU+00E9C3 A9%C3%A9
SPU+002020%20
cU+006363c
rU+007272r
èU+00E8C3 A8%C3%A8
mU+006D6Dm
eU+006565e
SPU+002020%20
&U+002626%26
SPU+002020%20
cU+006363c
rU+007272r
oU+006F6Fo
iU+006969i
sU+007373s
sU+007373s
aU+006161a
nU+006E6En
tU+007474t
sU+007373s
SPU+002020%20
/U+002F2F%2F
SPU+002020%20
éU+00E9C3 A9%C3%A9
tU+007474t
éU+00E9C3 A9%C3%A9
SPU+002020%20
2U+0032322
0U+0030300
2U+0032322
6U+0036366
Reference

Which encoder escapes which character

RFC 3986 splits ASCII into unreserved characters, which never need escaping, and reserved characters, which carry structure and therefore have to be escaped when they appear inside a value. Letters, digits, and the four marks hyphen, full stop, underscore and tilde are unreserved and are left alone by every encoder here, so they are not listed.

Each ASCII punctuation character with its RFC 3986 group and how each of the four encoders writes it
CharByteRoleComponentWhole URLFormRFC 3986
SP20Always escapedSpace%20%20+%20
!21Sub-delimiterExclamation mark!!%21%21
"22Always escapedDouble quote%22%22%22%22
#23General delimiterHash, starts the fragment%23#%23%23
$24Sub-delimiterDollar sign%24$%24%24
%25Always escapedPercent sign, starts an escape%25%25%25%25
&26Sub-delimiterAmpersand, separates parameters%26&%26%26
'27Sub-delimiterApostrophe''%27%27
(28Sub-delimiterOpen parenthesis((%28%28
)29Sub-delimiterClose parenthesis))%29%29
*2ASub-delimiterAsterisk***%2A
+2BSub-delimiterPlus sign%2B+%2B%2B
,2CSub-delimiterComma%2C,%2C%2C
-2DUnreservedHyphen----
.2EUnreservedFull stop....
/2FGeneral delimiterSlash, separates path segments%2F/%2F%2F
:3AGeneral delimiterColon, follows the scheme%3A:%3A%3A
;3BSub-delimiterSemicolon%3B;%3B%3B
<3CAlways escapedLess than%3C%3C%3C%3C
=3DSub-delimiterEquals, splits key from value%3D=%3D%3D
>3EAlways escapedGreater than%3E%3E%3E%3E
?3FGeneral delimiterQuestion mark, starts the query%3F?%3F%3F
@40General delimiterAt sign, ends the credentials%40@%40%40
[5BGeneral delimiterOpen bracket, wraps an IPv6 host%5B%5B%5B%5B
\5CAlways escapedBackslash%5C%5C%5C%5C
]5DGeneral delimiterClose bracket, wraps an IPv6 host%5D%5D%5D%5D
^5EAlways escapedCaret%5E%5E%5E%5E
_5FUnreservedUnderscore____
`60Always escapedBacktick%60%60%60%60
{7BAlways escapedOpen brace%7B%7B%7B%7B
|7CAlways escapedPipe%7C%7C%7C%7C
}7DAlways escapedClose brace%7D%7D%7D%7D
~7EUnreservedTilde~~%7E~
A greyed cell means the character survived untouched. Every row is generated by running the same four encoders this page uses, so the table cannot drift away from the output above it.
How it works

One character, several right answers.

Percent-encoding replaces a character with a percent sign and the hex value of each of its UTF-8 bytes. The hard part was never the mechanism, it is the question of which characters to replace, and there is no single answer to that. A slash between two path segments is structure and must stay bare; the same slash inside a filename is data and has to become %2F. A space is %20 under RFC 3986 and a plus sign under the form encoding a browser actually sends. An exclamation mark survives encodeURIComponent and is escaped by a strict RFC 3986 encoder, which is exactly why an OAuth signature computed with the wrong one fails to verify. This page refuses to choose for you: it applies all four rule sets to the same input, labels each with the situation it belongs to, and lets you copy the one that fits.

  1. 01

    Say which job you are doing

    Encoding one value is not the same job as encoding a whole URL, and neither is the same as taking a link apart. Pick encode, decode, parse a URL, or the query workbench, and the workspace changes to match. Each job keeps its own text, so switching between them loses nothing.

  2. 02

    Read every answer, not just one

    Encode mode shows the same text under all four rules at once, each labelled with when it is the right one and each separately copyable. Decode mode shows the component reading, the form reading where a plus sign is a space, and a repeated decode that reports how many layers it unwrapped. Parse mode splits the link into scheme, credentials, host in both its readable and its punycode form, port, path segments, query parameters, and fragment.

  3. 03

    Copy the piece you need, or rebuild the link

    Every output has its own copy button, so there is no hunting through a wall of text. In parse mode and the query workbench you can edit a value, add a parameter, remove one, or change the order, and the link is rebuilt from the table with everything encoded again correctly.

For broken redirects, mangled parameters, and suspicious links

Every encoding, an honest decoder, and the whole link taken apart.

Four encodings at once, each labelled with its job

Component encoding for a single value, whole-URL encoding for an assembled link, form encoding for anything a browser posts, and RFC 3986 strict for signatures. They disagree about the space, the plus sign, the slash, the exclamation mark, the apostrophe, the tilde, and the asterisk, and every one of those disagreements has broken somebody's query string. Seeing all four together is faster than remembering which function does what.

A decoder that names the fault and points at it

The browser built-in throws a bare URIError that tells you nothing. This one walks the string itself and reports the character position, the offending sequence, and the reason: a percent sign with no hex digits after it, a pair that is not hex, a byte that can only appear mid-character, an overlong encoding, a surrogate half, or a code point past the end of Unicode. A caret is drawn under the exact spot.

Double encoding detected and counted

%2520 is a space that went through an encoder twice, and it is the single most common reason a redirect parameter stops working. Repeated decoding runs until the text stops changing, reports how many layers came off, and lists each intermediate string so you can see where the extra pass was added.

Both forms of an internationalised host

A domain written in Cyrillic, Greek, or German with umlauts is resolved as punycode, and the two forms are shown side by side. This is the check that catches a homograph link: the readable host looks familiar while the ASCII form that DNS actually receives does not. Punycode is decoded here in the page, since a browser offers no way back from the ASCII form on its own.

A query workbench that respects repeated keys

tag=a&tag=b is two values, not one, and a parser that quietly keeps only the last one loses data. Parameters are listed as separate rows in their original order, and you can edit, add, remove, and reorder them, then copy the rebuilt string with the space written as a plus sign or as %20, whichever the receiving system expects.

A byte view and a reference table that cannot drift

An accented letter becomes two percent triplets, a CJK character three, an emoji four, which is why an encoded string can be several times longer than what you typed. The byte view shows that character by character, and the reference table lists every ASCII punctuation mark with its RFC 3986 role and how each of the four encoders writes it. Both are generated by the same code that produces the output above them.

Encoding questions

Plus signs, %2520, punycode, and why the built-in decoder throws.

What is the difference between encodeURI and encodeURIComponent?+

encodeURIComponent encodes one piece of a URL and assumes that piece is data, so it escapes the delimiters that give a URL its shape: the slash, the question mark, the hash, the ampersand, the equals sign, the colon, the at sign, the plus sign, and the dollar sign. encodeURI encodes a URL that is already assembled and assumes those delimiters are structure, so it leaves them alone. The practical rule is that you almost always want the component version, because you are almost always building a URL out of pieces rather than fixing one that already exists. Reach for the whole-URL version only when someone has handed you a complete link with a space or an accented character in it that needs cleaning up.

Why is a space sometimes %20 and sometimes a plus sign?+

Because two standards were written at different times and both survived. RFC 3986, which describes URLs generally, encodes a space as %20 everywhere. The older HTML form submission format, application/x-www-form-urlencoded, encodes a space as a plus sign, and that is what browsers still send when a form is submitted and what URLSearchParams produces. Both are read correctly inside a query string by essentially every server, because query string parsers know about both conventions. The trouble starts when a value encoded one way is decoded by the other: decode a form-encoded value with a plain percent decoder and a name like Anna Marie comes out as Anna+Marie. That is why this page shows both readings of a decode rather than picking one for you.

What does %2520 mean?+

It means a space that was percent-encoded twice. A space first becomes %20. If that %20 is then passed through an encoder again, the percent sign itself gets encoded as %25 and you end up with %2520. Seeing %25 followed by two more hex digits anywhere in a link is the fingerprint of a double encode. It usually happens when a redirect parameter is built by encoding a URL that had already been encoded, or when a value passes through two frameworks that each helpfully encode it. Paste it into decode mode here and the layer count tells you exactly how many passes to undo.

Which characters actually have to be encoded?+

RFC 3986 defines an unreserved set that never needs escaping: A to Z, a to z, 0 to 9, and the four marks hyphen, full stop, underscore, and tilde. Everything else falls into the reserved set, which is split into general delimiters (colon, slash, question mark, hash, square brackets, at sign) and sub-delimiters (exclamation mark, dollar, ampersand, apostrophe, parentheses, asterisk, plus, comma, semicolon, equals). A reserved character is legal where it is doing its structural job and must be escaped where it is data. Beyond that, space and the characters double quote, less than, greater than, percent, backslash, caret, backtick, and the braces are not allowed to appear raw at all. The reference table on this page lists each one with how the four encoders treat it.

Why does one accented letter become two percent codes?+

Because percent-encoding operates on bytes, not on characters, and modern URLs carry text as UTF-8. In UTF-8 the letter e with an acute accent is two bytes, C3 and A9, so it encodes as %C3%A9. A CJK character is three bytes and becomes three triplets, and an emoji is four bytes and becomes four triplets, which is twelve characters for one visible symbol. That is why an encoded string can be several times longer than the text you typed, and why a length limit measured in characters behaves differently before and after encoding. The byte view on this page shows the expansion character by character.

Can I just encode the whole URL to be safe?+

No, and this is the mistake that produces the most broken links. Running an already-correct URL through an encoder turns every structural character into an escape: the slashes become %2F, the question mark becomes %3F, and any existing escape has its percent sign turned into %25. What comes out is no longer a URL, it is a string that happens to look like one. If the link already works, leave it alone. If a link has a raw space or an accented character in it, whole-URL encoding is the right tool, because it fixes those without touching the delimiters. Try the already encoded preset in encode mode to see exactly what re-encoding does to a healthy link.

What is punycode, and why does the host look different from what I typed?+

The domain name system only carries a restricted set of ASCII characters, so a domain written in Arabic, Cyrillic, Greek, Chinese, or simply with a German umlaut has to be translated into ASCII before it can be looked up. That translation is punycode, and it produces labels that start with xn--. The browser does this conversion silently, which means the host you read and the host that is actually resolved are two different strings. Showing both is a security check, not a curiosity: a homograph attack works precisely because a name built from lookalike characters reads as a familiar brand while resolving to something else entirely. This page decodes punycode back to Unicode in the browser, since there is no built-in way to reverse it.

Is it safe to put a username and password in a URL?+

Treat any credential that has appeared in a URL as already leaked. The user information part of a URL, everything before the at sign, is sent in the clear as part of the request line on older protocols, gets written to server access logs and proxy logs, is stored in browser history, and has historically leaked through the Referer header sent to the next site you visit. Some browsers now strip it or warn about it, but the copies already written to logs do not go away. If a link with credentials in it has been shared, pasted into a ticket, or clicked from an email, rotate the password rather than relying on the link staying private. This page flags credentials whenever it finds them and masks the password rather than displaying it.

Why does decodeURIComponent throw, and what should I do instead?+

It throws a URIError whenever the input is not a valid percent-encoded UTF-8 string, which covers a percent sign with nothing after it, a pair that is not hex such as %ZZ, a truncated multi-byte character such as a bare %C3, an overlong encoding, and an escaped surrogate half. The error names neither the position nor the cause, so in production it usually turns into a blank page or a 500. The fix in your own code is to wrap the call and handle the failure explicitly rather than letting it escape. The fix while debugging is to paste the value here: the decoder on this page walks the string by hand and tells you which character is at fault and why, instead of refusing to say.

Is anything I paste sent to a server?+

No. Every encoder, the decoder, the URL parser, the punycode decoder, and the query workbench all run in this tab as plain JavaScript, and no link is ever fetched. That matters here more than on most tools, because the URLs people bring to a decoder are exactly the ones that contain session tokens, signed download links, password reset parameters, and internal hostnames. Input is capped at 100,000 characters, which is far beyond any usable URL, and nothing is stored between visits.

More focused tools, ready when you are.

Explore the growing collection for calculations, documents, writing, and everyday work.

Browse all tools