Certain characters have special meaning in URLs. When you want to use them as data (not as delimiters), you must percent-encode them.
Key Takeaways
- 1? starts the query string—encode as %3F in values
- 2& separates parameters—encode as %26 in values
- 3= separates keys from values—encode as %3D in values
- 4# starts the fragment—encode as %23 to include literally
- 5Spaces become + in query strings or %20 in paths
"URIs include components and subcomponents that are delimited by characters in the 'reserved' set. If data for a URI component contains characters that would conflict with a reserved character's purpose as a delimiter, then the conflicting data must be percent-encoded before the URI is formed."
Reserved Characters
URLs use 18 reserved characters as structural delimiters. When your data contains these characters, you must encode them so they're treated as literal values rather than URL structure. Failing to encode reserved characters is one of the most common sources of URL bugs, affecting roughly 1 in 10 web applications according to security audits.
The table below shows each reserved character, its encoded form, and its structural role in URLs. Understanding these roles helps you recognize when encoding is necessary.
| Character | Encoded | URL Role |
|---|---|---|
| ? | %3F | Starts query string |
| & | %26 | Separates parameters |
| = | %3D | Key-value separator |
| # | %23 | Starts fragment |
| / | %2F | Path separator |
| : | %3A | Scheme/port separator |
| @ | %40 | User info separator |
| + | %2B | Space in query (or literal +) |
| % | %25 | Encoding prefix |
Notice that % itself must be encoded as %25. This is crucial because % signals the start of an encoded sequence. If you have literal text like "100%" in a parameter value, you must encode the percent sign to prevent it from being misinterpreted.
Now let's see these encoding rules in action with practical JavaScript examples that demonstrate common scenarios you'll encounter in web development.
Encoding Examples
// Problem: & breaks the URL
const broken = 'https://example.com/search?q=Tom & Jerry';
// Server sees: q=Tom, Jerry= (broken!)
// Solution: Encode the value
const url = new URL('https://example.com/search');
url.searchParams.set('q', 'Tom & Jerry');
console.log(url.href);
// "https://example.com/search?q=Tom+%26+Jerry"
// Other examples
url.searchParams.set('equation', '1+1=2');
// "equation=1%2B1%3D2"
url.searchParams.set('tag', '#trending');
// "tag=%23trending"The code above demonstrates why the URL API is your safest choice for building URLs. When you use searchParams.set(), the ampersand in "Tom & Jerry" is automatically encoded to %26, preventing it from being interpreted as a parameter separator. The URL API handles all reserved characters correctly.
Space characters deserve special attention because they have two valid encodings depending on context. Understanding when to use + versus %20 prevents subtle bugs.
Handling Spaces
Spaces can be encoded two ways in URLs: as + or as %20. The correct choice depends on where the space appears. Using the wrong encoding won't always break your URL, but it can cause issues with certain servers or parsers.
| Context | Space Becomes | Example |
|---|---|---|
| Query string (form) | + | q=hello+world |
| Path | %20 | /hello%20world |
| JSON/JS encoding | %20 | Always uses %20 |
// URLSearchParams uses + for spaces
const url = new URL('https://example.com/search');
url.searchParams.set('q', 'hello world');
console.log(url.search); // "?q=hello+world"
// encodeURIComponent uses %20
encodeURIComponent('hello world'); // "hello%20world"
// Both decode correctly
decodeURIComponent('hello+world'); // "hello+world" (literal +)
new URLSearchParams('q=hello+world').get('q'); // "hello world"This example highlights an important gotcha: decodeURIComponent() treats + as a literal plus sign, while URLSearchParams treats it as a space. This difference exists because + for spaces is specific to form-encoded query strings (application/x-www-form-urlencoded), not general URL encoding.
While reserved characters require encoding, many common characters are safe to use without encoding. Knowing these safe characters helps you avoid unnecessary encoding.
Safe Characters
The "unreserved" characters are always safe to use in any part of a URL without encoding. These 66 characters (letters, digits, and four symbols) can appear literally in URLs and will always be interpreted as data, never as structure.
A-Z a-z 0-9
- _ . ~While you can encode these safe characters (and servers will decode them correctly), doing so unnecessarily increases URL length and reduces readability. The URL API is smart enough to leave these characters unencoded when building URLs.