URL Encoding Explained: A Developer's Complete Reference

Published February 15, 2026

Every URL you construct in an application passes through encoding rules that most developers understand only partially. URL encoding — officially called percent-encoding — exists because URLs are restricted to the ASCII character set and a subset of ASCII characters have reserved meaning in URL syntax. Understanding when and how to encode URLs prevents security vulnerabilities, broken links, API integration failures, and frustrating edge cases.

What Is Percent-Encoding?

Percent-encoding converts characters to a safe format for use in URLs. A character is converted to its UTF-8 byte representation, then each byte is written as %XX where XX is the two-digit hexadecimal value of that byte.

Examples:

For non-ASCII characters, UTF-8 encoding is applied first. The emoji 😀 (U+1F600) encodes in UTF-8 as F0 9F 98 80, which becomes %F0%9F%98%80 in percent-encoding.

Reserved vs Unreserved Characters

RFC 3986 defines which characters have structural meaning in URLs and which don't:

Unreserved Characters

Safe characters that never need encoding:

Reserved Characters

Characters with structural meaning in URLs:

Character Usage Example
: Scheme separator https:
/ Path separator /path/to/resource
? Query start ?key=value
# Fragment start #section
& Parameter separator &key=value
= Key-value separator key=value

Key rule: Reserved characters must be encoded when used as data (not structure). The reserved characters are structural — they define URL format. When you want to pass a reserved character as data, encode it.

encodeURI vs encodeURIComponent: The Critical Difference

JavaScript provides two encoding functions. They differ in which characters they preserve:

encodeURI()

Encodes a complete URL. Preserves reserved characters because they are structurally meaningful.

encodeURI("https://example.com/search?q=hello world")
// Result: "https://example.com/search?q=hello%20world"
// Note: : / ? are NOT encoded

encodeURIComponent()

Encodes a URL component (a value that will appear inside a URL). Encodes ALL special characters.

encodeURIComponent("hello world")
// Result: "hello%20world"

encodeURIComponent("user@example.com")
// Result: "user%40example.com"  (@encoded)

When to Use Which?

WRONG — encodeURI for query parameters:

const search = "hello & goodbye";
const url = "https://example.com?q=" + encodeURI(search);
// Result: https://example.com?q=hello & goodbye
// BROKEN: & is preserved, interpreted as parameter separator!

CORRECT — encodeURIComponent for query values:

const search = "hello & goodbye";
const url = "https://example.com?q=" + encodeURIComponent(search);
// Result: https://example.com?q=hello%20%26%20goodbye
// CORRECT: &is encoded, treated as data

Building Query Strings Correctly

To construct a query string with multiple parameters, apply encodeURIComponent to both keys and values:

const params = {
  name: "Alice Smith",
  email: "alice@example.com",
  tags: "javascript, typescript"
};

const queryString = Object.entries(params)
  .map(([key, value]) =>
    encodeURIComponent(key) + "=" + encodeURIComponent(value)
  )
  .join("&");

const url = "https://api.example.com/users?" + queryString;
// Result: https://api.example.com/users?name=Alice%20Smith&email=alice%40example.com&tags=javascript%2C%20typescript

Or use the modern URLSearchParams API, which handles encoding automatically:

const params = new URLSearchParams({
  name: "Alice Smith",
  email: "alice@example.com"
});

const url = "https://api.example.com/users?" + params.toString();
// Result: name=Alice+Smith&email=alice%40example.com
// (URLSearchParams uses + for spaces in query strings)

Common Encoding Mistakes

Double-Encoding

Encoding an already-encoded URL encodes the % itself:

const encoded = "hello%20world";
encodeURIComponent(encoded);
// Result: "hello%2520world"  (% becomes %25)
// WRONG: now decoding gives "hello%20world", not "hello world"

Solution: Check if input is already encoded before encoding.

Forgetting to Encode Spaces

Spaces must be encoded as %20 (or + in query strings per legacy convention, though %20 is more reliable).

// WRONG
"https://example.com/search?q=hello world"

// CORRECT
"https://example.com/search?q=hello%20world"

Browser Auto-Encoding Illusion

Browsers auto-encode URLs you paste in the address bar, so manual URLs often "work" despite being technically invalid. This leads developers to overlook encoding. Always encode programmatically.

Decoding URLs

decodeURI() and decodeURIComponent() are the inverse functions. You need to decode when:

// Extract search param value
const params = new URLSearchParams(window.location.search);
const q = params.get("q");  // Automatically decoded
console.log(q);  // "hello world" (not "hello%20world")

Tools That Help

For quick URL encoding/decoding and query string building, use the DevTools URL Encoder/Decoder. It handles:

Remember: Use encodeURIComponent() for query parameter values. Use encodeURI() only for complete URLs. When in doubt, encodeURIComponent() is the safe choice for data values.