5 Ways to Encode URLs in JavaScript

07 Mar 2026 1,816 words

5 Ways to Encode URLs in JavaScript

URL encoding in JavaScript is essential for handling user input and special characters in web requests. When you construct URLs dynamically in JavaScript, you must ensure that special characters are properly encoded so that the URL remains valid and is interpreted correctly by servers. Characters like spaces, ampersands, question marks, and non-ASCII characters have special meanings in URLs and must be percent-encoded (replaced with % followed by their hexadecimal ASCII value). Understanding the differences between encoding methods prevents bugs related to malformed URLs, broken API calls, and security vulnerabilities like injection attacks.

Why URL Encoding Matters

URL encoding (also known as percent-encoding) converts characters that are not allowed in URLs into a format that is safe for transmission over the internet. The URL specification (RFC 3986) reserves certain characters for special purposes and defines which characters are allowed unencoded. For example, spaces are not allowed in URLs and must be encoded as %20 or +. Ampersands (&) are used to separate query parameters and must be encoded if they appear in parameter values. Non-ASCII characters like é or ñ must be encoded using UTF-8 percent-encoding. Without proper encoding, URLs can break in several ways: spaces cause the URL to be truncated, ampersands split query parameters incorrectly, unencoded UTF-8 characters may not survive network transmission, and special characters in path segments can be misinterpreted by the server. Proper URL encoding ensures that data arrives intact and is interpreted correctly.

Understanding the URL Character Set

To use the right encoding method, you need to understand which characters are allowed in URLs without encoding. RFC 3986 defines unreserved characters that can be used as-is: uppercase and lowercase letters (A-Z, a-z), digits (0-9), and the characters hyphen (-), underscore (_), period (.), and tilde (~). Reserved characters have special meanings in specific URL contexts: colon (:), slash (/), question mark (?), hash (#), square brackets ([]), at sign (@), exclamation (!), dollar ($), ampersand (&), apostrophe ('), parentheses (()), asterisk (*), plus (+), comma (,), semicolon (;), and equals (=). These reserved characters should only be used unencoded if they serve their intended purpose in the URL structure; otherwise, they must be percent-encoded. All other characters, including spaces, Unicode characters, and control characters, must always be encoded.

Method 1: encodeURI()

The encodeURI() function encodes a complete Uniform Resource Identifier (URI), preserving characters that are part of the URI syntax. It encodes all characters except A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #. This makes it suitable for encoding entire URLs where the URL structure (scheme, host, path) should remain intact:

encodeURI('https://example.com/my path/');
// https://example.com/my%20path/

Notice that encodeURI() preserves the colon after https, the slashes, and the hash if present. This is the correct function to use when you have a complete URL string and you need to encode only the user-supplied portions. However, encodeURI() will NOT encode characters that have special meanings within URL components, such as & and = in query strings. This is a common source of bugs — using encodeURI() on a URL with query parameters that contain special characters will produce an incorrectly encoded URL:

encodeURI('https://example.com/search?q=hello world&lang=en');
// https://example.com/search?q=hello%20world&lang=en

While the space is encoded, the & is not encoded because encodeURI() considers it a valid URI character. This is correct behavior for the URL structure, but if the q value itself contained &, the result would be broken.

Method 2: encodeURIComponent()

The encodeURIComponent() function encodes a URI component by encoding ALL special characters, including those that encodeURI() preserves. It encodes everything except A-Z a-z 0-9 - _ . ! ~ * ' ( ). This makes it the correct choice for encoding query parameter values, path segments, and any user-supplied data that will be inserted into a URL:

encodeURIComponent('name=John & age=25');
// name%3DJohn%20%26%20age%3D25

This function encodes the equals sign, the ampersand, spaces, and other reserved characters, ensuring that the resulting string can be safely inserted into any part of a URL without breaking the URL structure. The most common pattern for building query strings is to use encodeURIComponent() on each parameter name and value separately:

function buildQueryString(params) {
  const parts = [];
  for (const [key, value] of Object.entries(params)) {
    parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
  }
  return parts.join('&');
}

const query = buildQueryString({
  name: 'John & Company',
  age: 25,
  city: 'San José'
});
// name=John%20%26%20Company&age=25&city=San%20Jos%C3%A9

This example shows proper handling of special characters and Unicode across multiple query parameters.

Method 3: URLSearchParams API

The URLSearchParams API provides a modern, convenient way to handle URL query parameters. It automatically handles encoding, making it the recommended approach for building and manipulating query strings:

const params = new URLSearchParams({ name: 'John', age: 25 });
console.log(params.toString()); // name=John&age=25

The URLSearchParams API offers several methods for working with query parameters beyond simple construction. You can append multiple values to the same parameter using the append method. You can iterate over all parameters with the entries, keys, and values methods. You can check for the existence of a parameter with has. You can delete parameters with delete. You can convert the parameters to a query string with toString. Additionally, URLSearchParams integrates seamlessly with the URL API for building complete URLs:

const url = new URL('https://example.com/api/search');
url.searchParams.set('q', 'hello world');
url.searchParams.set('page', '2');
url.searchParams.set('filter', 'active');

console.log(url.toString());
// https://example.com/api/search?q=hello+world&page=2&filter=active

Note that URLSearchParams uses + for spaces instead of %20, which is the standard encoding for application/x-www-form-urlencoded content type. Both + and %20 are valid representations of spaces in query strings, and servers handle both correctly. For path segments, however, you should use encodeURIComponent() as the + encoding is not valid in URL paths.

Method 4: Manual String Encoding

For cases where you need fine-grained control over the encoding process or want to implement encoding in environments without access to built-in functions, you can roll your own URL encoder:

function manualEncode(str) {
  return str.replace(/[^\w\s]/gi, c => '%' + c.charCodeAt(0).toString(16).toUpperCase());
}

This function replaces any character that is not a word character (\w matches [A-Za-z0-9_]) or whitespace with its percent-encoded hexadecimal representation. However, this simple implementation has several limitations. It does not handle Unicode characters correctly — for characters with code points above 255, you need UTF-8 encoding rather than simple UTF-16 code points. It does not encode spaces as %20 (it leaves them as-is). A more complete manual encoder would handle these cases:

function manualEncodeFull(str) {
  let result = '';
  for (let i = 0; i < str.length; i++) {
    const char = str[i];
    if (/[A-Za-z0-9\-_.!~*'()]/.test(char)) {
      result += char;
    } else if (char === ' ') {
      result += '%20';
    } else {
      const code = str.charCodeAt(i);
      if (code < 128) {
        result += '%' + code.toString(16).toUpperCase();
      } else {
        // Simple UTF-8 encoding for code points above 127
        const utf8 = encodeURIComponent(char);
        result += utf8;
      }
    }
  }
  return result;
}

Manual encoding is generally not recommended for production use since built-in functions handle edge cases more reliably, but understanding the mechanics is valuable for debugging and for implementing custom encoding logic when needed.

Method 5: Using a Third-Party Library

For complex URL manipulation scenarios involving nested objects, arrays, and custom serialization, third-party libraries offer additional capabilities beyond what native JavaScript provides. The query-string library is the most popular choice:

const queryString = require('query-string');

// Nested objects
const result = queryString.stringify({
  user: { name: 'John', roles: ['admin', 'editor'] }
});
// user%5Bname%5D=John&user%5Broles%5D%5B0%5D=admin&user%5Broles%5D%5B1%5D=editor

// Arrays without indices
const result2 = queryString.stringify({ tags: ['js', 'url', 'encoding'] }, { arrayFormat: 'none' });
// tags=js&tags=url&tags=encoding

Other useful libraries include qs for more advanced nesting options, url-parse for URL parsing with consistent behavior across environments, universal-url for isomorphic URL handling (works in both Node.js and browsers), and URL from the Web API, which is now available in Node.js without polyfills. When choosing a library, consider whether you need features like nested parameter support, array handling, URL parsing alongside encoding, and cross-platform compatibility.

Comparison of Encoding Methods

Choosing the right encoding method depends on your specific use case. encodeURI() is best for encoding complete URLs where you need to preserve the URL structure, such as encoding a user-submitted URL before storing or processing it. encodeURIComponent() is the workhorse for encoding individual query parameters, path segments, and any user data inserted into URLs. URLSearchParams provides the most convenient API for building query strings and manipulating URL parameters in modern browsers and Node.js. Manual encoding is useful for learning and for specialized cases where built-in functions do not provide the exact behavior needed. Third-party libraries are best for complex scenarios involving nested objects, array serialization, and advanced URL parsing requirements.

Common Mistakes and Pitfalls

Several common mistakes lead to URL encoding bugs that are often subtle and hard to debug. The most frequent error is using encodeURI() instead of encodeURIComponent() for query parameter values, which fails to encode &, =, and other reserved characters. Another common mistake is double-encoding — encoding a string that is already encoded, resulting in %2520 (the %25 is the encoded %, so %2520 decodes to %20 rather than a space). Decoding with decodeURI() when encodeURIComponent() was used for encoding can also cause issues, as decodeURI() does not decode some characters that encodeURIComponent() encodes. Forgetting to encode user input in URL construction is the most dangerous pitfall, as it can lead to injection vulnerabilities and broken API calls. Assuming btoa() (Base64 encoding) is equivalent to URL encoding is another confusion — Base64 and percent-encoding serve completely different purposes and are not interchangeable.

Best Practices for URL Encoding in Production

For production code, follow these guidelines to ensure reliable URL encoding. Always use encodeURIComponent() for user-supplied values inserted into URLs, never encodeURI(). Use the URL API and URLSearchParams for building and modifying URLs in modern environments. Validate and sanitize user input before encoding — encoding is not a substitute for input validation. Be consistent with encoding and decoding — always use matching pairs of encode/decode functions. Test with edge cases including spaces, Unicode characters, reserved characters, and very long parameter values. Handle encoding errors gracefully with try-catch blocks, especially when dealing with malformed input or strings that cannot be encoded. For server-side Node.js applications, consider using the qs library for complex query parameter handling.

Conclusion

URL encoding is a fundamental skill for JavaScript developers that ensures data integrity and security in web applications. The five methods covered — encodeURI(), encodeURIComponent(), URLSearchParams, manual encoding, and third-party libraries — each serve different purposes and have distinct characteristics. For most modern applications, URLSearchParams combined with encodeURIComponent() for fine-grained control provides the best combination of convenience and reliability. Understanding when and how to use each method prevents the subtle bugs that arise from improperly encoded URLs, making your applications more robust and maintainable.


About this article

Learn 5 different ways to encode URLs in JavaScript with built-in functions and practical examples.

Help2Code Logo
Menu