CALCULATORCASTLE

URL Encode / Decode

Encode special characters in URLs for safe transmission and decode URL-encoded strings.

About

URL Encode / Decode

A web address can only carry a small set of characters safely. Everything else has to be written as a percent sign followed by two hexadecimal digits, and that is what the tool above does in both directions. Paste a link or a single value into the box, and the converted text appears as you type, together with a list of which characters changed and what they became.

Percent-encoding is the reason a search for hot tub travels as hot%20tub, and the reason a link pasted inside another link comes back as https%3A%2F%2F… instead of the address you started with. Nothing you type here leaves your browser, so query strings with tokens in them stay on your machine.

What URL encoding is

The rules for what an address may contain come from RFC 3986, published in 2005 and still the governing document. It allows a deliberately small alphabet. The letters A to Z in either case, the digits 0 to 9, and four punctuation marks: hyphen, period, underscore and tilde. Those are the unreserved characters. They mean nothing except themselves, they never need converting, and a well behaved encoder leaves them alone.

A second group is reserved. These characters are legal in a URL, but they carry structural meaning. A slash divides path segments. A question mark opens the query string. An ampersand separates one parameter from the next. A hash marks the start of the fragment. They are the punctuation that gives an address its shape, and while they are doing that job they stay as they are. The moment the same symbol turns up inside a value rather than between values, it has to be encoded, because otherwise nothing can tell the two uses apart.

Everything outside those two groups, spaces included, has no place in a URL at all. Encoding handles it mechanically: take the bytes of the character and write each byte as a percent sign plus its two hex digits. A space is byte 20 in hexadecimal, so a space becomes %20. A percent sign itself is byte 25, so it becomes %25.

GroupCharactersTreatment
UnreservedA–Z a–z 0–9 - . _ ~Never encoded
Reserved, general delimiters: / ? # [ ] @Kept when structural, encoded when data
Reserved, sub-delimiters! $ & ' ( ) * + , ; =Kept when structural, encoded when data
Everything elsespace " < > % { } | \ ^ `, accents, emojiAlways encoded

Why a slash inside a value has to change

The clearest way to see the problem is to put one address inside another. Say you want to send a page a link to come back to:

https://example.com/go?next=https://example.com/cart?id=7

A server reading that has no chance. It splits the query at the first question mark, then splits the rest at every ampersand and equals sign it finds. The second question mark looks like a mistake, and the parameter next ends up holding https://example.com/cart with the rest lost or attached somewhere else. The punctuation inside the value is competing with the punctuation that holds the address together.

Encode the value and the ambiguity goes away:

https://example.com/go?next=https%3A%2F%2Fexample.com%2Fcart%3Fid%3D7

Now the only question mark the parser can see is the real one, the only equals sign is the real one, and the value decodes back to exactly what you meant on the other side. That round trip is the whole point. Encoding is not a way of hiding text or making it safe in a security sense; it is a way of saying which characters are structure and which are content.

One value, or a whole address

This is where most encoding bugs start. There are two jobs and they need different treatment, which is why the tool above has both.

Use one value when you are building a single piece of a URL: a search term, a redirect target, a filename in a path. It encodes the delimiters as well, so a slash or ampersand inside your data cannot reach out and break the address around it. In JavaScript this is encodeURIComponent. It leaves only the unreserved set alone, plus the five legacy marks ! ' ( ) *.

Use whole URL when you already have a complete, correctly assembled address and you only want to repair what is unsafe in it. Spaces become %20, curly braces and angle brackets get encoded, and the structure is left standing. In JavaScript this is encodeURI. Run a full address through the first mode by mistake and you get a single unusable string; run a search term through the second by mistake and any slash in it silently becomes a path separator.

The strict RFC 3986 checkbox covers a small gap. The specification lists ! ' ( ) * as reserved sub-delimiters, but encodeURIComponent predates that document and leaves them alone. Most systems accept both. Tick the box when you are handing values to something fussy, such as an OAuth signature or an S3 request signer, where the exact byte string is part of a calculation.

Characters that are not English letters

Percent-encoding works on bytes, not on characters, and the modern web writes text as UTF-8. In UTF-8 an ASCII letter is one byte, a Greek or accented letter is two, most other scripts are three, and emoji are four. Each of those bytes becomes its own percent code, which is why one character can turn into several.

CharacterUTF-8 bytesEncoded
space20%20
&26%26
éC3 A9%C3%A9
ΩCE A9%CE%A9
🏠 (house)F0 9F 8F A0%F0%9F%8F%A0

The counter in the result panel shows characters in against characters out for exactly this reason. A line of plain English grows by a few percent. A line of Japanese roughly triples, because every character becomes three bytes and every byte becomes three printed characters.

Spaces, plus signs, and where forms differ

A space has two encodings in the wild and both are correct in their own context. In a path or an ordinary URL a space is %20. In data submitted by an HTML form, which uses the media type application/x-www-form-urlencoded, a space is written as a plus sign. That convention is older than RFC 3986 and it survives because every browser and every server framework still speaks it.

The practical rule: a plus sign in form data means a space, and a plus sign anywhere else means a plus sign. If you decode a captured query string and find words glued together with plus signs, tick treat + as a space in decode mode. If you are encoding a literal plus, for instance a phone number written as +1 555 0100, leave the box alone and let it become %2B, which is what the one value mode does.

Double encoding, and how to spot it

Encoding an already encoded string is the most common bug in this area. Because the percent sign is itself encoded as %25, a space that has already become %20 becomes %2520 on a second pass. The signature is easy to recognise once you have seen it: any %25 followed by two more hex digits, or text that reads as %253A and %252F where you expected %3A and %2F.

It happens when two layers both try to help, typically a template that encodes a value and a client library that encodes the finished URL again. Decode the string once here. If the result still contains percent codes, it was double encoded, and the fix is to remove one of the two encoding steps rather than to decode twice in production.

Which part of the address you are in

The rules shift slightly between the sections of a URL, which is worth knowing when a value looks fine but behaves oddly.

The host name is not percent-encoded at all. Domains in other scripts use Punycode instead, an ASCII transcription that starts with xn--, so an address is converted by a different mechanism before it ever reaches this stage. The path treats the slash as a separator, so a slash inside a single segment has to be %2F. The query string treats & and = as separators, so both need encoding inside a value. The fragment, everything after the hash, is never sent to the server; the browser keeps it, which is why analytics tools often cannot see it.

Small things worth getting right

Hex digits are case-insensitive when decoded, so %3a and %3A both give a colon, but RFC 3986 asks producers to write them in upper case, and this tool does. Unreserved characters should not be encoded even though it is legal: %41 decodes to A, but writing it that way stops two identical addresses from comparing as equal. Keep an eye on length as well. There is no limit in the specification, but around 2,000 characters some browsers and servers start truncating, and a long encoded value counts triple once it is full of accents.

One last habit. Query strings routinely carry session tokens and API keys, so pasting one into an unknown online converter hands those over to someone else's server. This page runs entirely in your browser and sends nothing anywhere, which you can confirm by loading it once and then working offline.

Common questions

Frequently asked questions

It is an encoded space. A space cannot appear in a web address, so it is written as a percent sign followed by the hexadecimal value of the space character, which is 20. When a browser or server decodes the address it turns %20 back into a space, so the value arrives exactly as it was typed.

Because the address has been encoded as a single value rather than treated as a structure. A colon is %3A and a slash is %2F, so https:// becomes https%3A%2F%2F. That is correct when the link is being carried inside another link, for example as a redirect parameter. If the whole address in your browser bar looks like that, one encoding step too many has been applied.

encodeURIComponent encodes one piece of data and converts the delimiters too, so a slash, ampersand or question mark inside your value cannot break the URL around it. encodeURI assumes it has been given a complete address and leaves those delimiters intact, fixing only characters that are unsafe anywhere, such as spaces. Use the first for a query parameter and the second for a finished link.

Use %20 everywhere except data submitted by an HTML form. Form submissions use the application/x-www-form-urlencoded media type, where a space is written as a plus sign for historical reasons. Both are still in daily use, so when you decode a captured query string, check which convention it followed before reading the result.

The letters A to Z in either case, the digits 0 to 9, and the four marks hyphen, period, underscore and tilde. RFC 3986 calls these unreserved. Everything else either carries structural meaning, in which case it depends on where it appears, or is unsafe and always has to be encoded.

Because it was encoded twice. The percent sign is itself encoded as %25, so a space that had already become %20 turns into %2520 on the second pass. It usually means two layers of your stack are both encoding the same value. Remove one of them rather than decoding twice.

No. It is a transport convention, not protection. Anyone can decode a percent-encoded string in a second, and encoding does nothing to hide or authenticate what it carries. Treat an encoded token as if it were written in plain text, and rely on HTTPS for confidentiality.

Because percent-encoding works on bytes rather than on characters, and UTF-8 stores an accented letter as two bytes. Each byte prints as a percent sign plus two hex digits, so e with an acute accent becomes %C3%A9. Characters from other scripts take three bytes and emoji take four, which is why an emoji encodes to twelve characters.