← Back to Blog

URL Encoding Mistakes Developers Still Make (and Fixes)

Developer ToolsMar 29, 2026·7 min read
URL encoding debugging

URL encoding bugs are subtle, persistent, and often discovered in production. A misplaced %20, a double-encoded ampersand, or a confused + vs space can break API calls, corrupt tracking data, and create security vulnerabilities. Let's fix the most common ones.

Test your encoding with our URL Encoder/Decoder tool — paste any string and see the encoded result instantly.

encodeURI vs encodeURIComponent

JavaScript has two built-in encoding functions, and using the wrong one is the #1 source of bugs:

FunctionEncodesPreservesUse for
encodeURISpaces, non-ASCII: / ? # [ ] @ ! $ & ' ( ) * + , ; =Encoding a full URL
encodeURIComponentEverything above + : / ? # @ ! $ & ' ( ) * + , ; =Only - _ . ~ and alphanumericsEncoding a query parameter value
// WRONG — encodeURI preserves & in query values
const url = 'https://api.example.com/search?q=' + encodeURI('tom & jerry');
// Result: https://api.example.com/search?q=tom%20&%20jerry
// The & is preserved — now it looks like a separate parameter!

// CORRECT
const url = 'https://api.example.com/search?q=' + encodeURIComponent('tom & jerry');
// Result: https://api.example.com/search?q=tom%20%26%20jerry

Rule of thumb: Use encodeURIComponent for individual values. Use encodeURI only when you have a complete URL that just needs non-ASCII characters encoded.

Double-Encoding Bugs

Double-encoding happens when an already-encoded string is encoded again:

const name = 'hello world';
const encoded = encodeURIComponent(name); // hello%20world
const doubled = encodeURIComponent(encoded); // hello%2520world
// %25 is the encoding of % itself!

This typically occurs when:

Detection

Look for %25 in URLs — it's almost always a sign of double-encoding. The sequence %2520 (double-encoded space) is the classic telltale.

The + vs %20 Confusion

In HTML form submissions (application/x-www-form-urlencoded), spaces become +. In standard percent-encoding (RFC 3986), spaces become %20.

This matters because:

// Safe decoding that handles both + and %20
function safeDecodeParam(value) {
  return decodeURIComponent(value.replace(/\+/g, '%20'));
}

UTF-8 Edge Cases

Non-ASCII characters like é, ü, 日本語, and emoji must be percent-encoded as their UTF-8 byte sequences:

encodeURIComponent('café')   // caf%C3%A9
encodeURIComponent('日本語')  // %E6%97%A5%E6%9C%AC%E8%AA%9E
encodeURIComponent('🔒')     // %F0%9F%94%92

Problems arise when:

Redirect and Callback URL Pitfalls

OAuth callbacks and redirect URLs are especially prone to encoding bugs:

// Building an OAuth redirect
const redirectUri = 'https://myapp.com/callback?source=oauth';
const authUrl = `https://provider.com/auth?redirect_uri=${encodeURIComponent(redirectUri)}`;
// Correct: the entire callback URL (including its own ?) is encoded as a single parameter value

Common mistakes:

These bugs often create open redirect vulnerabilities that attackers exploit for phishing.

Debug Checklist

When a URL isn't working as expected, check these in order:

  1. Look for %25 — indicates double-encoding
  2. Check + vs %20 — are spaces handled consistently?
  3. Inspect raw request — use browser DevTools Network tab to see the actual encoded URL sent
  4. Test with special characters — try & = ? # / in values to see if they break the URL structure
  5. Check Content-Type — is the server parsing as application/x-www-form-urlencoded or application/json?
  6. Verify decode at server — log the raw and decoded values on the server side

Safe Helper Functions

// Build a query string safely
function buildQueryString(params) {
  return Object.entries(params)
    .map(([key, value]) =>
      `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
    )
    .join('&');
}

// Use URLSearchParams (modern browsers + Node.js)
const params = new URLSearchParams({ q: 'tom & jerry', page: '1' });
const url = `https://api.example.com/search?${params}`;
// Correct: handles encoding automatically

Best practice: Use URLSearchParams or URL constructor instead of manual string concatenation. They handle encoding correctly by default.

FAQ

Why does + become a space?

This is a legacy from HTML form encoding (application/x-www-form-urlencoded), where spaces are encoded as +. In standard percent-encoding (RFC 3986), spaces are %20. The + convention only applies to query strings in form submissions, not to path segments or other URL parts.

How do I encode nested URLs correctly?

Use encodeURIComponent on the inner URL before placing it into the outer URL's query parameter. This encodes characters like :/? that would otherwise be interpreted as part of the outer URL's structure.

Why do signatures break after URL encoding?

Signatures are computed over exact byte sequences. If you sign a string before encoding (or after decoding), but verify it in encoded form (or vice versa), the bytes differ and the signature fails. Always normalize the encoding before signing.

Related Tools & Articles