URL Encoding Special Characters Guide

May 28, 20266 min read

URLs can only contain a limited set of ASCII characters — letters, digits, and a few reserved punctuation marks. Everything else must be percent-encoded: replaced by a % sign followed by two hexadecimal digits. Knowing which characters require encoding and when is essential for building correct links, query strings, and API requests.

Characters That Require Encoding

Reserved Characters

Reserved characters have special meaning in URL syntax. When they appear as data (not as delimiters), they must be encoded.

CharacterEncodedPurpose in URL Syntax
&%26Query parameter separator
=%3DKey-value assignment
?%3FQuery string start
#%23Fragment identifier
/%2FPath separator
:%3AScheme/port separator
;%3BParameter separator
@%40Authority delimiter
+%2BSpace (form encoding)
%%25Encoding prefix itself

Unsafe and Non-ASCII Characters

Characters that have no defined role in URLs, or that may be modified by transport layers, should always be encoded.

CharacterEncodedReason
Space%20 or +Not allowed in URLs
<%3CHTML injection risk
>%3EHTML injection risk
"%22Delimiter in HTML attributes
{ }%7B %7DUnsafe, often filtered
\%5CPath manipulation risk
``%7C
é%C3%A9Non-ASCII (UTF-8 encoded)
%E4%B8%ADNon-ASCII (UTF-8 encoded)

Space Encoding: %20 vs +

Spaces in URLs have two encodings, and the difference matters:

  • %20 — The standard percent-encoding defined by RFC 3986. Used in path segments and any part of the URL.
  • + — Defined by the application/x-www-form-urlencoded media type (HTML form submissions). Only valid in query strings.
// Correct: encode path spaces as %20
const path = '/files/my%20document.pdf';

// Correct: encode query spaces as + (form-style) or %20
const query = 'name=John+Doe';
const query2 = 'name=John%20Doe';  // Also valid in query strings

Mixing these up causes bugs. Decoding my+document.pdf as a path produces my+document.pdf (the + is literal), while decoding it as form data produces my document.pdf. Always use %20 for paths and either form for queries, but decode consistently.

Unicode Encoding

Non-ASCII characters are encoded as their UTF-8 byte sequence, with each byte percent-encoded:

Character:  é
Unicode:    U+00E9
UTF-8:      0xC3 0xA9
Encoded:    %C3%A9

Character:  中
Unicode:    U+4E2D
UTF-8:      0xE4 0xB8 0xAD
Encoded:    %E4%B8%AD

Character:  😊
Unicode:    U+1F60A
UTF-8:      0xF0 0x9F 0x98 0x8A
Encoded:    %F0%9F%98%8A

Modern browsers display Unicode characters in the address bar for readability, but the underlying bytes are always percent-encoded. You can verify this by copying a URL with non-ASCII characters and pasting it into a plain text editor.

Common Pitfalls

Double Encoding

Encoding an already-encoded string produces double-encoded output that breaks the URL:

const query = 'a=b&c=d';
const encoded = encodeURIComponent(query);     // a%3Db%26c%3Dd
const doubleEncoded = encodeURIComponent(encoded); // a%253Db%2526c%253Dd
// Decoding double-encoded string: a%3Db%26c%3Dd (still encoded!)

Never encode a full URL with encodeURIComponent. It encodes the :, /, and ? that are part of the URL structure. Use it only on individual parameter values.

Ampersand in Parameter Values

An unencoded & in a query parameter value truncates the value:

Wrong:  ?redirect=https://example.com?a=1&b=2
       → redirect = "https://example.com?a=1", b = "2" (separate param)

Right:  ?redirect=https%3A%2F%2Fexample.com%3Fa%3D1%26b%3D2
       → redirect = "https://example.com?a=1&b=2"

Slash Encoding in Paths

Some web frameworks decode %2F in path segments, while others treat it as a literal %2F. This causes routing discrepancies:

/files/path%2Fto%2Ffile → May route to /files/path/to/file OR /files/path%2Fto%2Ffile

If slashes in a path parameter are meaningful data, test your framework's behavior explicitly.

Key Takeaways

  • Reserved characters (&, =, ?, #, /) must be encoded when used as data, not delimiters.
  • Use %20 for spaces in paths; + is only valid in form-encoded query strings.
  • Unicode characters are percent-encoded as their UTF-8 byte sequences.
  • Never encodeURIComponent a full URL — only encode individual query values.
  • Double encoding is a common source of broken links; always encode exactly once.

Try It Yourself

Need to encode or decode a URL? Paste it into the URL Encoder to see each component properly percent-encoded, or decode an encoded URL to inspect its original form.