·8 min read·Encoding & Security

URL Encoding Explained: When and Why You Need It

Learn what URL encoding (percent-encoding) is, which characters need encoding, the difference between %20 and +, and how to encode URLs in JavaScript, Python, and PHP.

Try our free String Encoder / Decoder

Encode and decode URLs, HTML entities, Base64, and more in a pipeline.

Open Tool

What is URL Encoding?

URL encoding, also known as percent-encoding, is a mechanism defined in RFC 3986 for representing characters in a URI (Uniform Resource Identifier) that are not allowed or have special meaning. It works by replacing unsafe characters with a percent sign (%) followed by two hexadecimal digits representing the character's ASCII code point.

For example, a space character (ASCII 32, hex 20) becomes %20. The at-sign @ (ASCII 64, hex 40) becomes %40. This allows you to include arbitrary data in a URL without conflicting with the URL's own syntax.

Consider this search URL:

# Without encoding (broken):
https://example.com/search?q=fish & chips&lang=en

# With encoding (correct):
https://example.com/search?q=fish%20%26%20chips&lang=en

Without encoding, the & in "fish & chips" would be misinterpreted as a query parameter separator, and the server would see three parameters: q=fish , chips, and lang=en. URL encoding the ampersand as %26 and the spaces as %20 tells the server they are part of the value, not structural separators. You can try this with our String Encoder / Decoder to see the encoding in action.

Which Characters Need Encoding?

RFC 3986 divides characters into three categories:

Unreserved Characters (Never Encode)

These characters are safe to use anywhere in a URL without encoding:

A-Z  a-z  0-9  -  _  .  ~

That's it — 66 characters total. Everything outside this set may need encoding depending on its position in the URL.

Reserved Characters (Context-Dependent)

Reserved characters have special meaning in URL syntax. You must encode them when they appear as data (e.g., inside a query parameter value), but you must not encode them when they serve their structural purpose:

:  /  ?  #  [  ]  @  !  $  &  '  (  )  *  +  ,  ;  =

For example, / separates path segments — encoding it as %2F in the path would break the URL. But if your query value literally contains a slash, you should encode it.

All Other Characters (Always Encode)

Spaces, non-ASCII characters (like e, ü, CJK characters, emoji), and control characters must always be percent-encoded. For multi-byte UTF-8 characters, each byte is encoded separately. For example, the euro sign () is encoded as %E2%82%AC (three bytes in UTF-8).

Quick Reference Table

CharacterEncodedDescription
(space)%20Space character
!%21Exclamation mark
#%23Hash / fragment
$%24Dollar sign
&%26Ampersand
+%2BPlus sign
/%2FForward slash
=%3DEquals sign
?%3FQuestion mark
@%40At sign

%20 vs + for Spaces

You'll see spaces represented two ways in URLs: %20 and +. They are not interchangeable— they come from different specifications and apply to different parts of the URL.

  • %20 (RFC 3986) — The standard percent-encoding for a space character. Valid anywhere in a URL: path segments, query strings, fragments. This is the modern, universal standard.
  • + (application/x-www-form-urlencoded) — A legacy convention from HTML form submissions. The + sign represents a space only inside query strings when the content type is application/x-www-form-urlencoded. In the URL path, a literal + means a plus sign, not a space.
# Both valid in a query string:
/search?q=hello+world      (form-encoded)
/search?q=hello%20world    (percent-encoded)

# In a path, + is a literal plus:
/files/my+file.txt         (file named "my+file.txt")
/files/my%20file.txt       (file named "my file.txt")

Best practice: Use %20 for spaces unless you are specifically building application/x-www-form-urlencoded data (e.g., HTML form POST bodies). When in doubt, %20 always works.

encodeURI vs encodeURIComponent in JavaScript

JavaScript provides two built-in functions for URL encoding. Choosing the wrong one is one of the most common sources of URL bugs.

encodeURI()

Encodes a complete URL. It preserves all characters that have structural meaning in a URL, including :, /, ?, #, &, and =:

encodeURI("https://example.com/path?q=hello world&lang=en")
// "https://example.com/path?q=hello%20world&lang=en"
// Notice: :, /, ?, &, = are NOT encoded

encodeURIComponent()

Encodes a single value to be inserted into a URL. It encodes everything except unreserved characters (A-Z a-z 0-9 - _ . ~):

encodeURIComponent("hello world & goodbye")
// "hello%20world%20%26%20goodbye"
// Notice: & IS encoded because it's data, not a separator

// Correct usage — encode each value separately:
const name = "John & Jane";
const city = "New York";
const url = `/search?name=${encodeURIComponent(name)}&city=${encodeURIComponent(city)}`;
// "/search?name=John%20%26%20Jane&city=New%20York"

When to Use Which

  • encodeURI — Encoding a full URL string where you want to preserve the structure (rare in practice).
  • encodeURIComponent — Encoding individual query parameter values, path segments, or any user-supplied data injected into a URL. This is what you need 95% of the time.

For decoding, use the corresponding decodeURI() and decodeURIComponent(). Modern JavaScript also offers the URL and URLSearchParams APIs, which handle encoding automatically:

// Modern approach — URLSearchParams handles encoding for you:
const params = new URLSearchParams();
params.set("q", "fish & chips");
params.set("lang", "en");
console.log(params.toString());
// "q=fish+%26+chips&lang=en"

// Full URL construction:
const url = new URL("https://example.com/search");
url.searchParams.set("q", "hello world");
console.log(url.href);
// "https://example.com/search?q=hello+world"

URL Encoding in Python and PHP

Python: urllib.parse

Python's standard library provides several functions in urllib.parse:

from urllib.parse import quote, quote_plus, urlencode

# quote() — RFC 3986 percent-encoding (like encodeURIComponent)
quote("hello world & goodbye")
# "hello%20world%20%26%20goodbye"

# quote_plus() — form-encoded (spaces become +)
quote_plus("hello world & goodbye")
# "hello+world+%26+goodbye"

# Safe parameter — exclude chars from encoding:
quote("https://example.com/path", safe=":/?#[]@!$&'()*+,;=")
# "https://example.com/path" (unchanged — structure preserved)

# urlencode() — encode a dict of query params:
urlencode({"q": "fish & chips", "lang": "en"})
# "q=fish+%26+chips&lang=en"

PHP: urlencode vs rawurlencode

PHP mirrors JavaScript's split but with different function names:

<?php
// urlencode() — form-encoded (spaces become +)
echo urlencode("hello world & goodbye");
// "hello+world+%26+goodbye"

// rawurlencode() — RFC 3986 (spaces become %20)
echo rawurlencode("hello world & goodbye");
// "hello%20world%20%26%20goodbye"

// Building a query string:
echo http_build_query(["q" => "fish & chips", "lang" => "en"]);
// "q=fish+%26+chips&lang=en"
?>

Rule of thumb: Use rawurlencode (PHP) or quote (Python) for path segments. Use urlencode (PHP) or quote_plus (Python) for form data and query strings. For quick ad-hoc encoding, try our String Encoder / Decoder which supports URL encoding, Base64 encoding, and more.

Common URL Encoding Mistakes

These are the errors that trip up developers most often:

1. Double Encoding

Wrong
encodeURIComponent(encodeURIComponent(value)) // hello%2520world (%25 is the encoded %)
Correct
encodeURIComponent(value) // hello%20world

Double encoding happens when you encode an already-encoded string. The % itself gets encoded to %25, creating unreadable URLs. This commonly occurs when a framework or library encodes values automatically and you encode them again manually.

2. Encoding the Entire URL with encodeURIComponent

Wrong
encodeURIComponent("https://example.com/search?q=test") // https%3A%2F%2Fexample.com%2Fsearch%3Fq%3Dtest
Correct
const q = encodeURIComponent("test"); `https://example.com/search?q=${q}`

Using encodeURIComponent on a full URL encodes the structural characters (:, /, ?, =) which breaks the URL. Only encode the values being inserted.

3. Not Encoding + in Query Values

Wrong
/search?q=C++ programming // Server sees: q="C programming" (+ = space)
Correct
/search?q=C%2B%2B+programming // Server sees: q="C++ programming"

In query strings, + means space. If your data contains a literal plus sign, it must be encoded as %2B or the server will interpret it as a space.

4. Forgetting to Encode User Input

Wrong
redirect_url = f"/profile/{username}" // If username is "../admin" → path traversal!
Correct
redirect_url = f"/profile/{quote(username, safe='')}" // "../admin" → "..%2Fadmin" (safe)

Failing to encode user-supplied data in URLs is a security risk. Unencoded input can lead to path traversal, open redirect, or injection attacks. Always encode user input with encodeURIComponent or equivalent.

5. Using encodeURI for Query Param Values

Wrong
const url = `/search?q=${encodeURI(userInput)}`; // If userInput is "a&b=c", & and = are preserved // Server sees q="a", b="c" (wrong!)
Correct
const url = `/search?q=${encodeURIComponent(userInput)}`; // "a&b=c" → "a%26b%3Dc" (correct)

encodeURI does not encode &, =, or other reserved characters. When building query parameters, always use encodeURIComponent to encode the values.

Frequently Asked Questions

What is the difference between encodeURI and encodeURIComponent?
encodeURI preserves URL structure characters like :, /, ?, #, and &, so it's safe for encoding an entire URL. encodeURIComponent encodes everything except unreserved characters (A-Z, a-z, 0-9, -, _, ., ~), making it the right choice for encoding individual query parameter values. In practice, you'll use encodeURIComponent 95% of the time.
Why does my URL break with special characters?
Characters like &, =, ?, and # have special meaning in URL syntax. An unencoded & in a query value is treated as a parameter separator, and an unencoded = splits a key from its value. To include these characters as data, you must percent-encode them (& becomes %26, = becomes %3D).
Should I encode the entire URL or just the query parameters?
Only encode the individual values you're inserting into the URL — not the URL structure itself. Encoding the entire URL would also encode :// and / which would break it. Build the URL structure manually (or use the URL API), and apply encodeURIComponent only to the dynamic values.
What is the difference between URL encoding and Base64 encoding?
They serve completely different purposes. URL encoding (percent-encoding) makes strings safe to include in URLs by replacing special characters with %XX codes. Base64 encoding converts arbitrary binary data into a text-safe string using 64 ASCII characters, commonly used for embedding images in CSS, sending binary data in JSON, or encoding email attachments. You can try both in our String Encoder / Decoder tool.

Encode & Decode URLs Now

Encode and decode URLs, HTML entities, Base64, and more in a visual pipeline. Free, private, runs in your browser.

Open String Encoder / Decoder

Related Tools