URL EncodingRFC 3986Web StandardsSecurityDeveloper Tools

URL Encoding & Percent-Encoding (RFC 3986): Reserved Characters, UTF-8 & Query Strings

URLs must survive transmission across thousands of proxies, gateways, and web servers without delimiter corruption. This comprehensive guide explains RFC 3986 percent-encoding: comparing unreserved and reserved character sets, examining JavaScript's encodeURI vs encodeURIComponent, explaining %20 versus '+', and highlighting double-encoding security flaws.

URL encoding guide illustration showing URI syntax, percent-encoding octets, and reserved character tables
Illustration for this guide: URL percent-encoding architecture and UTF-8 octet serialization.

The Uniform Resource Identifier (URI)—commonly referred to as a URL or web address—is the primary addressing protocol of the World Wide Web. When you click a link, submit an HTML search form, or trigger an API request, your browser must package destination hosts, path hierarchies, and query parameter key-value pairs into a standardized string that can be safely routed across thousands of intermediate proxy servers, routers, and firewalls.

Because URIs must be transmitted using a strictly limited subset of printable US-ASCII characters, transmitting spaces, punctuation marks, reserved delimiters (like &, =, and ?), or international Unicode characters (such as Arabic, Urdu, Chinese, or emojis) requires a deterministic translation mechanism known as URL encoding or percent-encoding.

This guide provides a comprehensive technical breakdown of percent-encoding standardized in IETF RFC 3986: examining reserved versus unreserved character sets, multi-byte UTF-8 octet conversions, the crucial difference between JavaScript’s encodeURI() and encodeURIComponent(), query string space encoding (%20 vs +), and security hazards like double-encoding vulnerabilities.

Encode & Decode URLs with Real-Time Accuracy

Safely encode query parameters or decode complex percent-encoded strings with full multi-byte UTF-8 support. 100% private in-browser tool.

Open URL Encoder / Decoder

RFC 3986 Character Classifications: Unreserved vs. Reserved

IETF RFC 3986 partitions all possible characters into three distinct operational categories:

1. Unreserved Characters (Never Encoded)

These 66 characters have zero syntactic role in URL parsing and are guaranteed never to be percent-encoded:

A-Z, a-z, 0-9, hyphen (-), underscore (_), period (.), tilde (~)

2. Reserved Characters (Delimiter Syntax)

These characters serve as structural delimiters separating the protocol scheme, authority, path, query string, and fragment identifiers:

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

If a reserved character is used for its literal data value (e.g. an ampersand inside a company name like “AT&T”), it must be percent-encoded (into %26) so the parser does not mistake it for a parameter separator.

3. Other / Non-ASCII Characters

Any character outside US-ASCII—including whitespace, control codes, accented vowels (é, ü), non-Latin scripts (Arabic, Urdu, Cyrillic, Kanji), and emojis—cannot exist natively in a URI and must be converted to UTF-8 byte sequences before percent-encoding.

How Percent-Encoding Works: Octets to %XX

The percent-encoding algorithm converts a single 8-bit byte into a triplet: the percent character % followed immediately by two hexadecimal digits representing the byte’s numeric value.

For multi-byte characters in modern UTF-8, characters require between 2 and 4 bytes. Each individual byte is separately percent-encoded:

Raw InputUnicode Code PointUTF-8 Hex BytesPercent-Encoded Output
Space ( )U+00200x20%20
Ampersand (&)U+00260x26%26
Slash (/)U+002F0x2F%2F
é (e with acute)U+00E90xC3 0xA9%C3%A9
Rocket (&U+1F680;)U+1F6800xF0 0x9F 0x9A 0x80%F0%9F%9A%80

JavaScript: encodeURI() vs. encodeURIComponent()

One of the most persistent bugs in web development is choosing the wrong JavaScript encoding function. The two functions serve completely different architectural goals:

encodeURI(fullUrl)

Designed to encode a complete, existing URL. It deliberately preserves all valid URL delimiters: : / ? # & = @ + $ ,.

encodeURI("https://site.com/search?q=C++ & Java")
→ "https://site.com/search?q=C++%20&%20Java"

Danger: Does NOT encode & or =, meaning query parameters will break!

encodeURIComponent(paramValue)

Designed to encode a single query parameter key or value. It aggressively encodes all reserved delimiters including / ? & = :.

encodeURIComponent("C++ & Java")
→ "C%2B%2B%20%26%20Java"

Best Practice: Always wrap individual parameter values with encodeURIComponent!

Spaces in URLs: Why Both %20 and ‘+’ Exist

Developers often wonder why some URLs encode spaces as %20 while others use the plus sign (+). This difference stems from two conflicting historical standards:

  • RFC 3986 (Canonical Percent-Encoding): Mandates that spaces must be encoded as %20 everywhere in a URI (in path segments, query strings, and fragments).
  • HTML Form Specification (application/x-www-form-urlencoded): A legacy web convention defined in HTML 4/5 where submitted form data encodes spaces as +. In query strings, search engines like Google interpret ?q=hello+world as two separate search terms.

In the path portion of a URL (e.g. /files/my+document.pdf), + is treated as a literal plus sign, NOT a space. Use %20 in path segments.

Internationalized Domains: Why Hostnames Use Punycode, Not Percent-Encoding

A frequent source of architectural confusion among web developers is the difference between how international characters are handled in the path of a URL versus the domain name (hostname):

Path & Query: Percent-Encoding (RFC 3986)

Non-ASCII characters in paths, query strings, and fragments are converted into multi-byte UTF-8 octets and prefixed with %:

/café → /caf%C3%A9

Hostname: Punycode (RFC 3492 / IDNA)

Domain Name System (DNS) servers strictly reject percent symbols. Internationalized Domain Names (IDNs) must be translated into an ASCII-Compatible Encoding (ACE) called Punycode:

münchen.de → xn--mnchen-3ya.de

Modern API Engineering: URLSearchParams vs. String Concatenation

Manual string concatenation is the leading cause of broken URLs and security vulnerabilities in client-side applications. Never construct query strings manually:

Flawed Manual Concatenation:// Breaks if search term contains &, =, or spaces!
const url = '/api/search?q=' + query + '&filter=' + filter;
Standard URLSearchParams (Safe):const params = new URLSearchParams();
params.set('q', query); // Automatically percent-encodes
params.set('filter', filter);
const url = '/api/search?' + params.toString();

Fragment Identifiers (#): Why Hashes Never Reach Web Servers

In a complete URI like https://example.com/docs#section-2, the character # introduces the fragment identifier.

Per RFC 3986 Section 3.5, fragment identifiers are strictly client-side routing directives. When your web browser issues an HTTP/HTTPS GET request across the network, the fragment identifier is completely stripped by the browser client before sending the request packets. The server never sees the hash string or any parameters placed after #. In modern Single Page Applications (SPAs) and React frameworks, fragment hashes are processed entirely inside browser memory to scroll to headings or manage local view state.

Cross-Browser Quirks: How Modern Browsers Handle Non-Standard Characters

While the WHATWG URL standard and IETF RFC 3986 define exact parsing algorithms, real-world web browsers exhibit subtle nuances when users paste raw characters into address bars versus when JavaScript executes network requests:

Visual Address Bar Display vs. Network Wire Format

To improve readability for non-English speakers, modern browsers (Chrome, Safari, Firefox) automatically render decoded UTF-8 characters in the visual address bar. If you visit /blog/caf%C3%A9, the URL bar displays /blog/café. However, the moment you copy that URL to your operating system clipboard, the browser automatically serializes it back to canonical percent-encoded ASCII (/blog/caf%C3%A9) to guarantee link portability when pasted into external applications.

Normalization of Unreserved Characters

Per RFC 3986 Section 2.3, unreserved characters (letters, numbers, -, _, ., ~) should never be percent-encoded. If an over-zealous encoder transforms the letter ‘A’ into %41, standard web servers automatically decode it back to ‘A’ during request routing. Two URLs differing only in percent-encoded unreserved characters are formally identical in web architecture.

Security Hazards: Double Encoding & Path Traversal

Double Encoding Vulnerabilities (OWASP)

A critical web security flaw occurs when an application decodes user input twice. For instance:

  1. An attacker crafts a directory traversal payload: %252E%252E%252F
  2. A web application firewall (WAF) inspects the input, decodes %25 to %, resulting in %2E%2E%2F, which does not look like raw ../ and passes inspection.
  3. The backend server performs a second decode pass, turning %2E%2E%2F into ../, allowing unauthorized filesystem traversal.

Summary & Practical Tools

Understanding percent-encoding is vital for robust web development, reliable API integrations, and secure data handling. Use our free, browser-based URL Encoder / Decoder to inspect, convert, and debug URLs with complete client-side privacy.

Sources & Official References

Formulas, protocol specifications, and standards cited in this guide are verified against official primary sources:

IETF RFC 3986: Uniform Resource Identifier (URI): Generic Syntax Internet Engineering Task Force (IETF)

The primary specification defining URI architecture, unreserved characters, and percent-encoding.

WHATWG URL Living Standard - Percent-Encoded Bytes Web Hypertext Application Technology Working Group (WHATWG)

Modern browser specification for URL parsing and form-urlencoded serialization.

Frequently Asked Questions

Clear answers to the most common questions regarding url encoding and practical everyday calculations.

What is the difference between encodeURI() and encodeURIComponent()?

encodeURI() is meant for a complete URL and preserves structural delimiters like ':', '/', '?', and '&'. encodeURIComponent() is meant for a single query parameter value and aggressively encodes all reserved characters so they do not break parameter boundaries.

Why do spaces in URLs sometimes encode as '+' and other times as '%20'?

RFC 3986 specifies '%20' as the universal percent-encoding for a space. However, HTML form submissions historically used the 'application/x-www-form-urlencoded' format, which represents spaces as '+'. In URL paths, '+' is a literal character, while in query strings it represents a space.

How are non-ASCII characters like emojis percent-encoded?

Non-ASCII characters are first converted into their UTF-8 byte representation (which requires 2 to 4 bytes). Each individual byte is then converted into a '%XX' hex pair. For example, the rocket emoji (U+1F680) converts into 4 bytes: '%F0%9F%9A%80'.

What is a double encoding attack?

A double encoding attack occurs when user input containing percent-encoded characters (like '%252E%252E%252F' for '../') is decoded twice by successive backend security layers, potentially bypassing Web Application Firewalls (WAFs) and enabling directory traversal.

Does this URL tool execute client-side?

Yes. All URL parsing, encoding, and decoding operations run 100% inside your browser using JavaScript's native decodeURIComponent and encodeURIComponent implementations. No URLs are logged or transmitted.