URL Encoding Special Characters

RFC 3986 splits URL characters into unreserved, reserved, and everything else. See the complete list of special characters, which ones need escaping, and why.

ZERO UPLOAD · ALL LOCAL
  1. The tool opens in DECODE mode. Paste a percent-encoded URL or string into the input field.
  2. The decoded output appears instantly. If the input contains a query string, each parameter is parsed into an editable table.
  3. Edit any value in the parameter table to see the rebuilt encoded query string update in real time.
  4. Switch to ENCODE mode to convert text to three encoding variants: encodeURIComponent, encodeURI, and form encoding with + for spaces.
  5. Click Copy next to any result to copy it to your clipboard.

Worked examples for this use case

An unreserved slug

Before
my-file_v2.final~draft
After
my-file_v2.final~draft

Letters, digits, hyphen, underscore, period, and tilde pass through both encoders unchanged.

A reserved character as data

Before
price:19.99
After
price%3A19.99

encodeURIComponent escapes the colon because it treats it as data, not as a URI scheme separator.

A reserved character as structure

Before
https://example.com/x
After
https://example.com/x

encodeURI leaves the colon and slashes intact because they are genuine structural delimiters here.

An always-encoded character

Before
quote "test"
After
quote%20%22test%22

The quotation marks and space fall outside both the unreserved and reserved sets, so both encoders escape them.

INPUT

DECODED OUTPUT
ENCODED OUTPUT
encodeURIComponent
encodeURI
Form encoding (+)

URL Encoding Special Characters: The Full Reserved and Unreserved Sets

RFC 3986 sorts every character a URL might contain into three groups, and knowing the groups explains why some punctuation needs escaping and some does not. Unreserved characters, letters, digits, and the four marks - _ . ~, are always safe and never require encoding.1 Reserved characters, the gen-delims : / ? # [ ] @ and the sub-delims ! $ & ' ( ) * + , ; =, carry structural meaning and must be encoded whenever they appear as literal data rather than as delimiters.2

Every other character, including space, quotation marks, angle brackets, and all non-ASCII text, falls outside both sets and must always be percent-encoded. Consequently, the question "does this character need escaping" always has the same answer: check which of the three groups it belongs to. The CapyToolkit encoder applies this classification automatically, so pasting any string reveals exactly which characters it altered.

The unreserved set that never needs escaping

Four characters have permanent free passage through a URL alongside letters and digits. RFC 3986 Section 2.3 names them explicitly: hyphen, underscore, period, and tilde, joined by the alphanumeric range A-Z, a-z, and 0-9. These four marks are not leftovers or conventions; they are the exact set the specification guarantees will never need percent-encoding in any position of a URL, from the first path segment through the final fragment.

Why these four marks stay stable everywhere

These characters are guaranteed to mean the same thing in every context of a URL, path, query, or fragment, because no delimiter in the grammar uses them. Consequently, an encoder never touches them regardless of position, and encodeURIComponent leaves all of them alone even though it escapes nearly everything else.3 This is also why file names, slugs, and identifiers built from letters, digits, and hyphens travel through URLs without any encoding step at all, a property web developers lean on constantly when designing readable paths. This stability is also why RFC 3986 calls the four marks out by name rather than leaving them open to interpretation, since a URI producer and a URI consumer that disagreed on even one of them would break compatibility across the entire web.

Gen-delims and sub-delims: reserved but conditional

Reserved characters occupy a middle ground: safe as structure, unsafe as data.4 RFC 3986 splits them into gen-delims, which separate the major components of a URI (: / ? # [ ] @), and sub-delims, which have meaning within a component (! $ & ' ( ) * + , ; =). The practical consequence is that whether a reserved character needs encoding depends on the role it plays in a specific URI component rather than on its identity alone.

Encoding depends on position, not identity

Understanding the colon exception right after a URL scheme explains why https: never needs escaping, even though that same colon turns dangerous the moment it shows up as literal data inside a path segment. An ampersand follows the identical logic: fine as a query delimiter, but corrosive to a value if left raw inside one.

This is why encodeURIComponent escapes every reserved character: it assumes you are handing it a single component where none of these characters should carry structural meaning.5 encodeURI, by contrast, trusts that you have already placed them correctly and leaves them alone. The correct escaping of a reserved character is therefore a question of role, not of the character itself. Recognizing which role a character plays in a given URI, delimiter or data, is the real skill behind correct encoding, more so than memorizing the character list.

A common mistake is to assume that because a character is safe in one position it is safe everywhere. A query parameter value containing & must encode that ampersand as %26, or the server will treat it as a delimiter and split the value into a new parameter. The same & between two parameters is correct as a literal delimiter and should never be encoded there. Both situations involve the same character, but only one of them requires escaping, which is why context is what determines correctness.

Everything else must always be encoded

Characters outside both the unreserved and reserved sets have no legal unencoded form anywhere in a URL2, which means every instance of these characters must be escaped before the string travels. This group includes the space, quotation marks, angle brackets, backtick, curly braces, pipe, backslash, and caret, along with the entire range of non-ASCII text such as accented letters, CJK characters, and emoji.

Furthermore, this is the largest and least memorable group, so the practical approach is not to memorize it but to let an encoder classify each character for you. encodeURIComponent and encodeURI both escape this entire category identically, since neither function ever treats these characters as safe. The only decision that changes between the two functions is how they treat the reserved set; the unreserved set and the always-encode set are handled the same way by both, which narrows the real decision to a much smaller question. Even punctuation that looks harmless, such as a caret or a backtick, has no defined meaning anywhere in the URI grammar, so a decoder cannot assume anything about it beyond the byte value the percent-escape spells out.

Why non-ASCII characters always encode

The same universal-escape rule applies to every non-ASCII character regardless of whether it looks like punctuation or prose. Because percent-encoding operates on UTF-8 bytes, a single accented letter can produce two or more escapes, and an emoji can produce four, but in every case the result is safe to include in any component of a URL. There are no exceptions based on language or script: if a character is outside the unreserved or reserved sets, both encodeURIComponent and encodeURI escape it in full.

When to use this

Consult this classification when you need to predict whether a character will survive encoding unchanged, or when auditing a URL-building function for correctness. Paste a string containing the character in question into CapyToolkit's ENCODE mode and compare the encodeURIComponent and encodeURI rows: an unreserved character stays identical in both, a reserved character differs between them, and everything else is escaped in both. This three-way split is a fast way to settle an argument about whether a given character "needs" encoding, since the answer is rarely a matter of opinion once you check which of the three groups it falls into.

Examples

An unreserved slug

Before
my-file_v2.final~draft
After
my-file_v2.final~draft

Letters, digits, hyphen, underscore, period, and tilde pass through both encoders unchanged.

A reserved character as data

Before
price:19.99
After
price%3A19.99

encodeURIComponent escapes the colon because it treats it as data, not as a URI scheme separator.

A reserved character as structure

Before
https://example.com/x
After
https://example.com/x

encodeURI leaves the colon and slashes intact because they are genuine structural delimiters here.

An always-encoded character

Before
quote "test"
After
quote%20%22test%22

The quotation marks and space fall outside both the unreserved and reserved sets, so both encoders escape them.

Sources
  1. 1.

    IETF, "Unreserved Characters," RFC 3986 Section 2.3, rfc-editor.org, January 2005. https://www.rfc-editor.org/rfc/rfc3986.html#section-2.3

  2. 2.

    IETF, "Reserved Characters," RFC 3986 Section 2.2, datatracker.ietf.org, January 2005. https://datatracker.ietf.org/doc/html/rfc3986#section-2.2

  3. 3.

    Mozilla Developer Network, "encodeURIComponent()," developer.mozilla.org, accessed July 2026. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

  4. 4.

    WHATWG, "URL Standard," url.spec.whatwg.org, accessed July 2026. https://url.spec.whatwg.org/

  5. 5.

    ECMA, "encodeURIComponent (uriComponent)," ECMAScript 2027 Language Specification, Section 18.2.6.1, tc39.es, July 2026. https://tc39.es/ecma262/#sec-encodeuricomponent-uricomponent

FAQ