Skip to main content
UtilitiesFree · no sign-up

URL Encoder and Decoder

Percent-encode a query value or decode one, with the component and full-URL rules kept apart.

Updated

Everything runs in your browser. Nothing is uploaded or written into the page URL. Percent-encoding is not sanitisation: it does not prevent XSS or SQL injection, and it is not a security control.

Component mode escapes the separators : / ? # & = because inside one value they would end it early. Full URL mode leaves them alone so the address still works.

Encoded output

https%3A%2F%2Fviralrang.com%2Fsearch%3Fq%3Dsalt%20%26%20pepper%2Bmix%26lang%3D%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9

Characters changed
14
Length in
61
Length out
120

What changed

  • : to %3A
  • / to %2F
  • ? to %3F
  • = to %3D
  • space to %20
  • & to %26
  • + to %2B
  • ا to %D8%A7
  • ل to %D9%84
  • ع to %D8%B9
  • ر to %D8%B1
  • ب to %D8%A8
  • ي to %D9%8A
  • ة to %D8%A9

Encoding is not escaping for safety. A percent-encoded value is still hostile input once it is decoded, so it does not stop cross-site scripting or SQL injection. Use parameterised queries and context-aware output escaping for that.

In short

When should I use encodeURIComponent instead of encodeURI?

Use component encoding for a single value and full URL encoding for a whole address. Component mode escapes the 11 characters ; / ? : @ & = + $ , and # so a value cannot break out of its slot. Full URL mode leaves them doing structural work. The input a b&c=d becomes a%20b%26c%3Dd one way and a%20b&c=d the other.

Percent-encoding is not sanitisation. It does not prevent cross-site scripting or SQL injection, and a decoded value is exactly as dangerous as it was before.

How to use the URL encoder and decoder

Paste on the left and the result updates as you type. While encoding, the panel lists every distinct character that changed and the percent triplet it became. While decoding, it shows the decoded text and, when the input looks like a query string, the individual key and value pairs.

The mode switch is the part most tools get wrong. Component encoding escapes the separators, because inside a single value an ampersand or an equals sign would end that value early and silently create a new parameter. Full URL encoding leaves those same characters alone, because in a whole address they are the structure.

66

Characters never escaped

62 alphanumerics plus - . _ ~

11

Escaped by component only

; / ? : @ & = + $ , #

3

Characters per byte

so one emoji costs 12

Everything outside the unreserved set becomes one triplet per UTF-8 byte, which is why non-Latin text grows so fast. A Latin letter with an accent is two bytes and six characters. An Arabic letter is two bytes. An emoji is four bytes and twelve characters, which is how a short link full of emoji turns into a very long one.

The plus sign is the classic bug. In plain percent-decoding a plus is a literal plus. In form-encoded data, which is what an HTML form and most query strings produce, a plus means a space. Apply the wrong rule and C++ comes back as C followed by two spaces, or a search for salt and pepper comes back with plus signs in it.

Nothing you paste leaves your browser. There is no upload and no logging, and the text is never written into the page URL, so a signed link or a session token pasted here does not end up in a shareable address or in a log somewhere else.

Do

  • Encode each query value separately, then join the pairs with ampersands yourself.
  • Use full URL mode when the whole address has to keep working.
  • Escape a literal plus as %2B whenever the value travels as form data.
  • Decode a query string by splitting on the separators first, then decoding each half.
  • Percent-encode a space as %20 in a path, where a plus is not a space.

Don't

  • Run encodeURIComponent over a finished URL and expect the link to survive.
  • Trust a decoded value because it arrived percent-encoded.
  • Encode a value twice, which turns every % into %25 and breaks the receiver.
  • Assume a plus in a path segment means a space, because there it does not.
  • Rely on the browser address bar display, which hides encoding it thinks is noise.

What each mode does to the characters that actually cause trouble, produced by the encoder on this page.

CharacterComponentFull URLWhy it matters
space%20%20Never legal in a URL, escaped by both modes
&%26&Separates parameters, so it must be escaped inside a value
=%3D=Splits a key from its value
?%3F?Starts the query string
#%23#Starts the fragment, which is never sent to the server
/%2F/Splits path segments
:%3A:Follows the scheme and precedes a port number
+%2B+Read as a space by form-encoded parsers
%%25%25Starts a triplet, so a literal percent must be escaped by both
~ - . _unchangedunchangedUnreserved in RFC 3986 section 2.3
é%C3%A9%C3%A9Two UTF-8 bytes, so two triplets
😀%F0%9F%98%80%F0%9F%98%80Four UTF-8 bytes, so twelve characters
Component mode is the encodeURIComponent rule and full URL mode is the encodeURI rule, both as implemented by the browser. Non-Latin characters are encoded one triplet per UTF-8 byte.

Reserved, unreserved, and what each mode touches

RFC 3986 splits the character space into three groups, and the whole scheme follows from them. Unreserved characters may always appear literally. Reserved characters have a structural meaning and must be escaped when they are data rather than structure. Everything else has no place in a URI at all and is always escaped.

Characters that are allowed in a URI but do not have a reserved purpose are called unreserved. These include uppercase and lowercase letters, decimal digits, hyphen, period, underscore, and tilde.
T. Berners-Lee, R. Fielding and L. Masinter, RFC 3986 section 2.3, January 2005
The three groups
Unreserved, 66 characters
A to Z, a to z, 0 to 9, and - . _ ~
Reserved gen-delims
: / ? # [ ] @
Reserved sub-delims
! $ & ' ( ) * + , ; =
Everything else
always escaped, including the space

One honest wrinkle: the browser function behind component mode leaves the exclamation mark, the asterisk, the apostrophe and both round brackets unescaped, even though RFC 3986 lists all five as reserved sub-delims. It predates the RFC. That is usually harmless, and worth knowing when a strict server disagrees.

Full URL mode escapes only the third group, so an address keeps working. Component mode escapes the second group as well, which is what makes it safe for a single value. Neither ever touches the first group, so a slug made of letters, digits and hyphens passes through both modes unchanged.

Better than encoding a title into a URL

A page title full of accents and punctuation percent-encodes into something unreadable. Turning it into a plain hyphenated slug first is almost always the better answer.

Open the slug generator

Why a plus sign sometimes means a space

Two different specifications are in play and they disagree. RFC 3986 defines percent-encoding for URIs and says nothing about the plus sign, so there a plus is simply a plus. The form-encoded serialisation, which HTML defines for what a form sends, encodes a space as a plus instead of as %20.

That second rule exists for historical reasons and it is not going away, because every HTML form and most search boxes on the web still emit it. So the same string can arrive with a space written two ways, and a decoder has to be told which rule to apply rather than guessing.

The same value under both rules
Sent by a form
q=salt+and+pepper
Decoded as form data
salt and pepper
Decoded as plain RFC 3986
salt+and+pepper
A literal plus, encoded
C%2B%2B
Safe under both rules
C++

A plus that was properly escaped as %2B survives either interpretation, which is the practical reason to escape it rather than to rely on the receiver picking the right rule.

The rule of thumb: tick the plus box for anything that came out of a query string or a form submission, and untick it for a path segment, a fragment, or a value you built by hand. When you are encoding, escape a real plus as %2B and the question never comes up.

The formula, worked line by line

Percent-encoding has one rule and no arithmetic. Take the character, take its UTF-8 bytes, and write each byte as a percent sign followed by two hexadecimal digits. The only question a tool has to answer is which characters get that treatment, and that is where the two modes differ.

Because the unit is the byte rather than the character, the cost of encoding depends entirely on the alphabet. Anything in the ASCII range is one byte and three characters. Latin with accents, Greek, Cyrillic, Hebrew and Arabic are two bytes. Most Chinese, Japanese and Korean characters are three, and emoji are four.

triplet = "%" followed by the byte in two hexadecimal digits
encoded length = 3 × the number of UTF-8 bytes needing escape
unreserved, never escaped: A-Z a-z 0-9 - . _ ~
component mode also escapes: ; / ? : @ & = + $ , #
form-encoded only: a space may be written + instead of %20
A reserved character becoming a percent tripletThe ampersand is byte 38 decimal, 26 in hexadecimal, so percent-encoding writes it as %26. Component mode escapes it because inside a query value an ampersand would end the value early. Full URL mode leaves & and = alone because there they are doing structural work, which is why the same input gives a%20b%26c%3Dd in one mode and a%20b&c=d in the other.CHARACTER TO BYTE TO TRIPLET&UTF-8 byte 38hex 26, bits 00100110%26percent, then the byte in hexadecimalinputa b&c=dcomponenta%20b%26c%3Ddfull URLa%20b&c=dboth escape the space; only component mode escapes & and =3 changed1 changed
One reserved character, one percent triplet, and the same input under both encoding modes.
One accented letter, one emoji
é as UTF-8
C3 A9, two bytes
é encoded
%C3%A9, six characters
The emoji as UTF-8
F0 9F 98 80, four bytes
The emoji encoded
%F0%9F%98%80, twelve characters
Cost per byte
3 characters, always

Both modes agree on these two, because neither an accented letter nor an emoji is in the unreserved set. The modes only disagree about the reserved characters, which is exactly the disagreement that matters.

Hexadecimal digits may be written in either case, so %c3%a9 and %C3%A9 decode identically. Uppercase is what RFC 3986 recommends and what browsers produce, and matching that convention makes two versions of the same URL compare equal instead of merely decoding equal.

Double encoding is the failure mode to watch for. Encode a value that was already encoded and every percent sign becomes %25, so %20 turns into %2520 and the receiver hands your code a literal percent two zero. If a value arrives looking like that, something in the chain encoded it twice.

Length limits are the other practical consequence. There is no limit in the specification, but implementations impose their own, and a common conservative ceiling is around 2,000 characters for a URL that has to work everywhere. Non-Latin text encoded at three characters a byte reaches that ceiling far sooner than it looks like it should.

Questions people ask

Sources

Where the constants and formulas on this page come from. Each line names the figure it backs.

  1. The unreserved set is ALPHA, DIGIT, hyphen, period, underscore and tilde, and producers should emit uppercase hexadecimal digits in percent-encodings.

    RFC 3986: Uniform Resource Identifier (URI): Generic SyntaxIETF, 2005

  2. In application/x-www-form-urlencoded serialisation a space becomes a plus rather than %20, which is why a plus decodes back to a space in form data but not in a path.

    URL StandardWHATWG