Benchvale

URL encoder

Percent-encoding replaces characters that would otherwise mean something in a URL. Component encoding and form-body encoding differ by more than a space: a form body also escapes characters encodeURIComponent leaves alone. This page shows those two plus encodeURI for a complete URL, rather than making you guess which one you have.

A developer sees, side by side, what a string becomes under each URL percent-encoding, and is told which one to use for the destination they actually have.

Encode or decode

Result

Decoded something larger? Send it to the tool chain to keep going.

Measured from what you pasted
In / out
·
Escaped
·
Arm
·
Requests
· from Resource Timing
Script
· KB of a 100 KB budget
Everything here runs in your browser. We never send your text to ourselves or anywhere else. It stays on your device. Once the page has loaded, you can disconnect and keep working. How we build tools

The same string, three encodings

Take hello world/foo?x=1. Component encoding is hello%20world%2Ffoo%3Fx%3D1, because a space, a slash, a question mark, and an equals sign would otherwise be URL syntax. Form-body encoding is hello+world%2Ffoo%3Fx%3D1: the same reserved characters, but a space becomes a plus. encodeURI for a complete URL is hello%20world/foo?x=1, because it leaves the delimiters in place. Paste that string here and the three rows should match those three strings.

Which encoding, by destination

A query value and a path segment want component encoding, where a space is %20. A form body wants application/x-www-form-urlencoded, where a space is +. A fragment is a component too. A complete URL that already has its delimiters in place wants encodeURI, which leaves : / ? # & = alone so the URL keeps working.

The plus sign, which is why you are here

There are two percent-encodings in daily use. They are not identical except for a space. On ~_.-!*() a, component encoding is ~_.-!*()%20a and form encoding is %7E_.-%21*%28%29+a. They differ for ~, !, (, ) and the space.

Component encoding is what encodeURIComponent produces. A space becomes %20. RFC 3986 section 2.3 names letters, digits, -, ., _ and ~ as unreserved; encodeURIComponent also leaves !, *, (, ) and ' literal, which that unreserved set does not. Use it for a single value going into a path segment, a query value or a fragment.

Form encoding is the application/x-www-form-urlencoded serializer, which is what an HTML form posts and what most server frameworks assume when they parse a query string. A space becomes +.

Encode one way, decode the other, and a space turns into a literal plus or a genuine plus turns into a space. That second one is the expensive version: a plus in an email address, a signature or a base64 string is meaningful, and turning it into a space corrupts the value rather than merely looking odd. The decode result row is decodeURIComponent, the widest of the three going backwards, and Copy first result copies that row. Encode-mode rows name encodings. Decode is not an encoding, so its set name is -. Raising the pass ceiling changes how many times decode runs, not the label. If the input contains a plus, both readings are printed beside it, labeled form data and RFC 3986, and neither of those labels is marked as chosen.

The third one, and when not to use it

encodeURI is for a complete URL, and it deliberately leaves : / ? # & = alone so the URL keeps working. That makes it exactly wrong for encoding one value: a value containing an ampersand or an equals sign will pass through untouched and then be read as a parameter boundary by the receiving server.

It is shown here because it is genuinely the right answer when the whole thing you are holding is a URL with a space in it. The set name beside that row says it matches no WHATWG encode set, because naming the nearest set would be a claim the row does not keep.

Hosts are not percent-encoding

A non-ASCII host is IDNA-encoded, not percent-encoded. Mixing the two is how a host gets percent-encoded when it should not. When the input parses as a URL, the parts table shows the host in the IDNA form the WHATWG parser produces, and says so beside that cell. The three encode rows still percent-encode the whole string, including the host, because that is what those three functions do.

Decoding a string that was encoded twice

When the decoded result is itself a URL, this breaks it into scheme, userinfo, host, port, path, query and fragment. Recursive decode sets a ceiling of 1 to 16 passes and then reports how many passes actually changed the string. If the input already contains a percent-escape, decode mode says so before you have to notice leftover percent signs.

One thing the parts table quietly demonstrates: the fragment, the piece after the #, is the only part of a URL a browser never sends to a server. That is why every tool on this site puts shareable state there.

What this deliberately does not do

It does not wrap output into 76-character lines. That wrapping is an RFC 2045 MIME convention, and a wrapped percent-encoded URL is not a URL. It does not take a file; per-line encode and decode cover the bulk job. It does not convert a host to punycode as its own product, and it does not do base64 or hex. Those are a different row.

The three named rows are UTF-8. There is no charset control on this page. Bytes in another charset belong with the fourth row, which is out of this version.

Questions

Which encoding should I use?

If you are building a query string by hand or putting a value into a path, use the component form with %20. If you are reproducing what a browser form would send, use the form body version with +. When you are decoding something and do not know its origin, look at both plus readings and pick the one that reads like real data.

Why does my decoded string still have percent signs in it?

It was probably encoded twice, which happens whenever a URL containing a value gets put inside another URL as a parameter. Raise the pass ceiling and decode again. If a %25 appears in the input, that is an encoded percent sign. It is consistent with double encoding, and it is also what a literal percent sign becomes after a single encode pass.

What does "not valid percent-encoding" mean?

A % has to be followed by exactly two hexadecimal digits. A stray percent sign in ordinary text, such as "50% off", is not valid encoded input, and a decoder that guessed at it would be inventing data. A well-formed escape that is not valid UTF-8 is the same class: the decoder rejects it rather than guessing.

Is my URL uploaded?

No. Encoding and decoding are both a few lines of arithmetic and both happen in this tab. That matters more than it sounds here: URLs routinely carry session tokens and API keys, and this is one of the tools people paste those into without thinking about it.

Related tools

For = padding rather than % escapes, you want base64. If the decoded value turns out to be JSON, the JSON formatter will indent it and locate any syntax error, and the tool chain will do both steps on one paste.

Maintained by Aaron Wilson
Published . Last updated . Method and formula: how we build tools. Something wrong? Tell us and it goes in the changelog.