URL Encoding Explained: When and Why You Need It

Developer Guide

What Is URL Encoding (Percent-Encoding)?

URL encoding, also called percent-encoding, is a mechanism for representing characters in a URL that would otherwise be unsafe or illegal. In its simplest form, a character is replaced by a percent sign followed by two hexadecimal digits representing the character's ASCII value.

For example, a space character becomes %20, and the forward slash / can become %2F when it needs to be treated as literal data rather than a URL separator.

You encounter URL encoding every day: bookmarks with query parameters, API endpoints, search queries, and file downloads. Without it, complex data couldn't safely travel through URLs.

Why URL Encoding Exists: RFC 3986 and Reserved Characters

URLs follow a strict specification defined in RFC 3986. The standard reserves certain characters for structural purposes:

  • : – scheme separator (http://...)
  • // – network path separator
  • @ – user info separator
  • ? – query string marker
  • # – fragment identifier
  • / – path segment separator
  • & – parameter separator in query strings
  • = – key-value separator

When these reserved characters appear as data (not structure), they must be encoded to avoid ambiguity. Additionally, URLs are constrained to ASCII characters; non-ASCII characters must be encoded.

How URL Encoding Works: The Technical Process

URL encoding follows a three-step process:

  1. Convert to UTF-8 bytes: The character is first encoded as UTF-8 bytes. For ASCII characters like "A", this is straightforward (65). For non-ASCII characters like "é", UTF-8 produces multiple bytes.
  2. Convert to hexadecimal: Each byte is converted to its two-digit hexadecimal representation.
  3. Add percent prefix: Each hex pair is prefixed with a percent sign.

Example: The character "é" encodes to UTF-8 bytes [0xC3, 0xA9], which become %C3%A9 in a URL.

Reserved vs. Unreserved Characters

Not all characters need encoding. RFC 3986 defines unreserved characters that are safe in URLs:

A–Z, a–z, 0–9, hyphen (-), underscore (_), period (.), tilde (~)

These characters never need encoding. Everything else—including reserved characters when used as data, spaces, and special symbols—must be percent-encoded in URLs.

Key takeaway: Encoding decisions depend on context. A forward slash is a structural character in paths but must be encoded when appearing in a query parameter value.

encodeURIComponent vs. encodeURI: The Critical Difference

JavaScript provides two encoding functions, and choosing the wrong one is a common bug. Here's the difference:

encodeURIComponent()

Encodes for use in query strings, form data, or path segments.

Encodes: : / ? # [ ] @ ! $ & ' ( ) * + , ; =

encodeURI()

Encodes a complete URI, preserving structural characters.

Does not encode: : / ? # [ ] @

Rule: Use encodeURIComponent() for individual query parameter values, path segments, and form data. Use encodeURI() only when encoding an already-formed URL string (rarely needed in modern code).

// ✅ Correct: encode the parameter value const search = "hello world"; const url = `/api/search?q=${encodeURIComponent(search)}`; // Result: /api/search?q=hello%20world

// ❌ Wrong: encodeURI doesn't encode query separators const url = encodeURI("/api/search?q=hello world"); // Result: /api/search?q=hello%20world (space encoded, but? is NOT)

Common URL Encoding Bugs

1. Double Encoding

Encoding a string that's already been encoded. If you receive an already-encoded parameter and encode it again, %20 becomes%2520.

const param = "hello%20world"; // already encoded const double = encodeURIComponent(param); // WRONG // double = "hello%2520world"

2. Forgetting to Encode

Directly concatenating user input into URLs without encoding. A user entering "[email protected]" without encoding breaks the URL structure.

// ❌ Broken const email = "[email protected]"; const url = `/api/users?email=${email}`; // Result: /api/[email protected] (@breaks parsing) // ✅ Fixed const url = `/api/users?email=${encodeURIComponent(email)}`; // Result: /api/users?email=user%40example.com

3. Encoding Entire URLs

Using encodeURIComponent() on a complete URL destroys its structure. Encode only the parts that are data.

URL Encoding in Different Contexts

Query Parameters

Encode each parameter value with encodeURIComponent(). The ? and & are unencoded (structure).

/search?q=hello+world&filter=category:tech

Path Segments

Encode each segment separately to preserve / as a separator.

/api/users/${encodeURIComponent(userId)}/profile

Form Data (application/x-www-form-urlencoded)

HTML forms encode data similarly to URLs. Most frameworks handle this automatically, but you can manually construct with URLSearchParams:

const params = new URLSearchParams({ email: '[email protected]', message: 'hello world' }); // URLSearchParams handles encoding automatically

Space Encoding: %20 vs. +

Spaces have two valid encodings in URLs: %20 and +. The plus sign is only valid in query strings under the application/x-www-form-urlencoded convention.

%20 – Universal (anywhere)

Safe for paths, fragments, and query parameters.

+ – Query strings only (form submission convention)

Modern JavaScript's encodeURIComponent() uses %20. If you need +, replace manually:

const encoded = encodeURIComponent("hello world"); const withPlus = encoded.replace(/%20/g, '+'); // "hello+world"

Try It Yourself

Understanding URL encoding is one thing; seeing it in action is another. Use our interactive URL encoder tools to test encoding in real-time and see exactly how different characters transform.

Key Takeaways

  • URL encoding converts unsafe characters into %XX format
  • Reserved characters have structural meaning; they must be encoded when used as data
  • Always use encodeURIComponent() for query parameters, path segments, and form values
  • Avoid double encoding by checking if data is already encoded
  • Different contexts (paths, query strings, form data) have slightly different rules
  • Use URLSearchParams to handle form data automatically