← All articles · May 4, 2026 · fmt.hjlabs.in

URL Encoding: Common Pitfalls and How to Avoid Them

URL encoding is one of those topics every developer thinks they understand — until they spend three hours debugging why a query string with an ampersand keeps breaking the API. This guide covers the surprising depth of URL encoding in 2026.

The basics: what URL encoding does

URLs can only contain a specific subset of ASCII characters. Anything outside (or special structural characters like ?, &, =, /, #) must be percent-encoded as % followed by the hex byte value.

Examples:

The encodeURI vs encodeURIComponent confusion

JavaScript has two functions, and using the wrong one causes the most common URL encoding bug:

FunctionEncodesUse for
encodeURI()spaces, special chars in URLEncoding a complete URL
encodeURIComponent()everything except a-z, 0-9, -, _, ., ~Encoding query parameter values

The crucial difference: encodeURI does NOT encode ?, &, =, / — because these are structural URL characters. encodeURIComponent encodes EVERYTHING that isn't unreserved.

The classic bug

// WRONG - encodeURI doesn't encode &
const url = 'https://api.com?q=' + encodeURI('tom & jerry');
// Result: https://api.com?q=tom%20&%20jerry
// API sees q=tom and a separate empty param!

// RIGHT - encodeURIComponent encodes &
const url = 'https://api.com?q=' + encodeURIComponent('tom & jerry');
// Result: https://api.com?q=tom%20%26%20jerry
// API sees q="tom & jerry" - correct!

Use URLSearchParams instead

Modern browsers and Node have URLSearchParams which handles encoding correctly:

const params = new URLSearchParams({
  q: 'tom & jerry',
  category: 'cartoons/animation'
});
const url = `https://api.com?${params}`;
// Result: https://api.com?q=tom+%26+jerry&category=cartoons%2Fanimation

This is the preferred approach in 2026 — it never encodes structural characters incorrectly and it handles edge cases.

Spaces: %20 vs + (the historical mess)

In query strings, spaces can be encoded two ways:

Both work for query strings on virtually all servers. encodeURIComponent outputs %20; URLSearchParams outputs +. Both decode correctly.

For path segments, only %20 is correct — + stays as a literal plus.

Double encoding

The "I encoded it but the server encoded it again" problem:

// You: encode "tom & jerry"
// Result: tom%20%26%20jerry

// Server framework auto-encodes the param again
// Result: tom%2520%2526%2520jerry
// Now decoded back: tom%20%26%20jerry (still encoded!)

Diagnosis: see %25 in the URL where you didn't put it. %25 is the encoding of % itself, so it's a smoking-gun sign of double encoding.

Unicode and the multi-byte trap

URL encoding works on bytes, not characters. UTF-8 multi-byte characters become multiple percent escapes:

"चाय" (Hindi: tea)
UTF-8 bytes: E0 A4 9A E0 A4 BE E0 A4 AF
Encoded: %E0%A4%9A%E0%A4%BE%E0%A4%AF

JavaScript's encodeURIComponent does this correctly. Other languages may need explicit UTF-8 conversion first.

What you don't need to encode

RFC 3986 "unreserved" characters — never encoded:

"Reserved" characters that should be encoded if they appear in a value (not as a delimiter):

URL parts and their encoding rules

PartExampleEncoding
SchemehttpsNever needs encoding
Hostapi.example.comIDN punycode for non-ASCII
Path/users/123Encode special chars within segments, not /
Query?q=helloUse URLSearchParams
Fragment#sectionEncode special chars

IDN: Internationalized Domain Names

Domain names with non-ASCII (e.g., ऒग-ङ.जठ) use Punycode encoding:

Decoding pitfalls

  1. Decoding before splitting. If you decode ?q=tom%26jerry before splitting on &, the %26 becomes & and you split incorrectly.
  2. Trusting decoded input. A decoded URL parameter can contain anything — XSS, SQL injection, path traversal. Always validate after decoding.
  3. Decoding twice. If your framework already decodes, decoding again corrupts data.

Tools

Bottom line

Use URLSearchParams in 2026 — it handles encoding correctly. If you must use encodeURIComponent, never use it on a full URL — only on individual values. Watch for %25 in URLs as a sign of double encoding. Validate every decoded value before use.

Try the free dev tools suite

15+ tools. 100% client-side. No signup. No tracking.

Browse all tools →

More from the blog