Common URL Encoding Mistakes and How to Fix Them

May 28, 20266 min read

URL Encoding Errors Break Things Quietly

URL encoding mistakes rarely throw obvious errors. Instead, they produce broken links, missing query parameters, corrupted file downloads, or authentication failures that are difficult to trace. Understanding the common pitfalls helps you write correct URL-handling code from the start.

Mistake 1: Double Encoding

How It Happens

Double encoding occurs when you encode a string that already contains percent-encoded sequences. The % characters in the existing encoding get encoded again as %25:

// Original string
const city = 'São Paulo';

// First encoding (correct)
const encoded = encodeURIComponent(city); // "S%C3%A3o%20Paulo"

// Second encoding (broken)
const doubleEncoded = encodeURIComponent(encoded); // "S%25C3%25A3o%2520Paulo"

Where It Creeps In

Double encoding often appears when multiple layers of a stack each apply encoding:

  • A client library encodes a parameter, then the HTTP client encodes it again
  • A template engine URL-encodes a value that was already encoded in the controller
  • A redirect URL includes encoded query parameters, and the redirect handler encodes the entire URL

The Fix

Decode before re-encoding, or encode only once at the boundary where the URL is constructed:

// Safe: encode only at the final construction point
const url = `https://api.example.com/search?q=${encodeURIComponent(rawQuery)}`;

// If you receive a pre-encoded value, decode it first
const decoded = decodeURIComponent(receivedValue);
const url = `https://api.example.com/search?q=${encodeURIComponent(decoded)}`;

Mistake 2: Using the Wrong Encoding Function

encodeURI vs encodeURIComponent

These two functions encode different character sets, and using the wrong one breaks URLs in predictable ways:

const url = 'https://example.com/path?name=John Doe&city=New York';

// encodeURI preserves URL structure — use for full URLs
encodeURI(url);
// "https://example.com/path?name=John%20Doe&city=New%20York"

// encodeURIComponent encodes everything — use for parameter values only
encodeURIComponent(url);
// "https%3A%2F%2Fexample.com%2Fpath%3Fname%3DJohn%20Doe%26city%3DNew%20York"
// ↑ Broken: :, /, ?, & are all encoded
ScenarioCorrect FunctionWhy
Building a full URLencodeURIPreserves :, /, ?, #, &
Encoding a query parameter valueencodeURIComponentEncodes & and = to avoid parameter injection
Encoding a path segmentencodeURIComponentEncodes / to avoid path traversal

Mistake 3: Not Encoding Reserved Characters in User Input

Reserved characters like &, =, #, and ? have special meaning in URLs. When user input contains these characters unencoded, the URL structure breaks:

// User searches for "AT&T"
const query = 'AT&T';
const url = `https://example.com/search?q=${query}`;
// Results in: https://example.com/search?q=AT&T
// Server reads q="AT" and an empty parameter "T"

// Correct
const safeUrl = `https://example.com/search?q=${encodeURIComponent(query)}`;
// Results in: https://example.com/search?q=AT%26T

This mistake enables parameter injection attacks when unsanitized user input creates URLs.

Mistake 4: Encoding Spaces Incorrectly

URLs represent spaces in two ways:

  • %20 — percent-encoding (standard)
  • + — application/x-www-form-urlencoded encoding (form submissions)
// encodeURIComponent uses %20
encodeURIComponent('hello world'); // "hello%20world"

// Form encoding uses +
const formData = new URLSearchParams({ q: 'hello world' });
formData.toString(); // "q=hello+world"

Mixing these conventions causes mismatches. A server expecting %20 may treat + as a literal plus sign, and vice versa.

The Fix

Use encodeURIComponent for URL path segments and query parameters in API calls. Use URLSearchParams for form-encoded request bodies. Never substitute + for %20 manually.

Mistake 5: Encoding the Entire URL at Once

Encoding a complete URL with encodeURIComponent makes it unusable — the protocol, host, and path separators all get encoded:

// Broken approach
const fullUrl = 'https://api.example.com/users?role=admin&page=1';
const encoded = encodeURIComponent(fullUrl);
// "https%3A%2F%2Fapi.example.com%2Fusers%3Frole%3Dadmin%26page%3D1"
// Cannot be used as a valid URL

// Correct: encode components individually
const base = 'https://api.example.com/users';
const params = new URLSearchParams({ role: 'admin', page: '1' });
const url = `${base}?${params}`;
// "https://api.example.com/users?role=admin&page=1"

Mistake 6: Assuming URL Encoding Is Encryption

Percent-encoding is trivially reversible. It provides zero confidentiality:

// "Encrypted" with URL encoding — trivially decoded
const encoded = encodeURIComponent('password123'); // "password123"
// ↑ Same string, no encoding needed for ASCII chars

const encodedInt = encodeURIComponent('sëcrët'); // "s%C3%ABcr%C3%ABt"
// Decode: decodeURIComponent("s%C3%ABcr%C3%ABt") → "sëcrët"

Never use URL encoding as a security measure. Use TLS for data in transit and encryption for sensitive values.

Key Takeaways

  • Double encoding turns %XX into %25XX — decode before re-encoding
  • Use encodeURIComponent for parameter values, encodeURI for full URLs
  • Reserved characters in user input must be encoded to prevent parameter injection
  • Spaces are %20 in URLs but + in form encoding — know which context you are in
  • Encode URL components individually, never the entire URL string
  • URL encoding is not encryption — it is trivially reversible

Try It Yourself

Encode and decode URLs correctly with our free URL Encoder. Paste any text to see its percent-encoded form, or paste an encoded URL to decode it — all processing happens locally in your browser.

Try the URL Encoder →