Web

URL Encoding Explained: When and Why Characters Are Percent-Encoded

Learn why URLs need encoding, how percent-encoding works, and when to use encodeURIComponent vs encodeURI in real applications.

7 min read

You've seen %20 in a URL and wondered what it means. You've had a URL break in mysterious ways when it contained an ampersand. URL encoding is the unsung hero of the web — and the source of countless bugs when you misunderstand it.

What is URL encoding?

URL encoding (officially called percent encoding) is a way to represent characters in a URL that would otherwise have special meaning, or that aren't allowed at all. Each unsafe character is replaced with a percent sign followed by two hex digits representing its byte value.

space → %20 · & → %26 · ? → %3F · / → %2F · é → %C3%A9

The result is a URL that contains only ASCII letters, digits, and a small set of punctuation — guaranteed to survive transmission through any system that follows the HTTP and URI specs.

Try the encoder: Paste any string and see the encoded form instantly:

Open URL Encoder →

Why do we need it?

URLs have a strict grammar. Specific characters separate components:

  • ? separates the path from the query string
  • & separates query parameters from each other
  • = separates a parameter name from its value
  • # introduces the fragment identifier
  • / separates path segments

If your data contains any of these characters, it must be encoded. Otherwise the URL parser cannot tell where one part ends and the next begins.

Consider a search query for black & white. Without encoding, the URL ?q=black & white&page=1 would parse as three parameters: q=black , white, and page=1. With encoding, ?q=black%20%26%20white&page=1 parses correctly.

encodeURIComponent vs encodeURI

JavaScript provides two encoding functions, and the difference matters.

encodeURIComponent — escapes everything

Use this when you're encoding part of a URL — a query string value, a path segment, a fragment. It escapes ?, &, =, /, and almost everything else except letters, digits, and a handful of safe punctuation marks.

encodeURI — preserves URL structure

Use this when you have a complete URL that contains spaces or unicode characters, but where the URL structure (the slashes, query separators, etc.) should be preserved as-is.

Input: https://example.com/search?q=hello world

encodeURI: https://example.com/search?q=hello%20world

encodeURIComponent: https%3A%2F%2Fexample.com%2Fsearch%3Fq%3Dhello%20world

Common pitfalls

  • Double encoding: If you encode something twice (encode the encoded result), you get%2520 where you wanted %20. Decoding once returns the encoded form, not the original. This breaks form submissions and URL handlers in subtle ways.
  • Plus sign confusion: In query strings, historically + meant a space (legacy from form submissions). Modern encodeURIComponent uses %20 for spaces. If you need to handle legacy URLs, replace + with space before decoding.
  • Forgetting unicode: Non-ASCII characters like é, 中, 🚀 must be encoded as their UTF-8 byte sequence — multiple percent-escapes for a single character.

Practical examples

  • Search forms: ?q=encodeURIComponent(userInput) — always encode user-provided search terms.
  • OAuth redirects: redirect_uri=encodeURIComponent(callbackUrl) — the callback URL contains ? and & that must not collide with the outer URL's structure.
  • API path with user IDs: /users/${encodeURIComponent(id)} — protects against user IDs containing slashes.

When you can skip it

For URLs you control entirely (hardcoded paths to your own assets), you don't need to encode. The risk comes when any part of the URL is user-provided or dynamic. In that case, encode the dynamic part to be safe.