Why URLs Have Character Restrictions
Percent-encoding represents bytes in a URL as % followed by two hexadecimal digits, allowing data such as a space to be expressed without confusing URL delimiters. The rules depend on which part of the URL is being built; RFC 3986 describes the URI syntax and character categories.
The fundamental problem: the internet is global and text is diverse, but early web protocols were designed around ASCII - a 128-character encoding that covers English letters, digits, and a limited set of symbols. A space character, a Chinese character, a hashtag, or a quotation mark each has special or ambiguous meaning within URL syntax. If these characters appeared unencoded in URLs, parsers would either misinterpret them or break entirely.
URL encoding - formally called percent-encoding - solves this by providing a way to represent any character in a URL-safe format. Every character that isn't explicitly "allowed" in a particular URL position gets replaced with a percent sign followed by its two-digit hexadecimal ASCII (or UTF-8) code. Space becomes %20. Ampersand becomes %26. The hash symbol becomes %23.
Reserved vs. Unreserved Characters
RFC 3986 divides URL characters into two key categories:
Unreserved Characters (Always Safe - Never Need Encoding)
These 66 characters can appear anywhere in a URL without encoding:
- Uppercase letters: A-Z
- Lowercase letters: a-z
- Digits: 0-9
- Four symbols: hyphen (-), underscore (_), period (.), tilde (~)
If your URL contains only these characters, you never need to worry about encoding.
Reserved Characters (Have Special Meaning - Context-Dependent)
These characters are part of URL syntax - they delimit URL components or serve specific functions:
- General delimiters: : / ? # [ ] @
- Sub-delimiters: ! $ & ' ( ) * + , ; =
Reserved characters must be percent-encoded when they appear in a URL component where they would otherwise be misinterpreted. For example, a # in a URL path should be encoded as %23 because an unencoded # signals the start of a URL fragment to parsers - if you're using it as part of a filename, that misinterpretation breaks your URL.
The Percent-Encoding Mechanism
Percent-encoding works as follows:
- Take the character that needs encoding
- Find its byte representation in UTF-8 (for ASCII characters, UTF-8 is the same as ASCII)
- Express each byte as two hexadecimal digits
- Prepend a percent sign:
%XX
Example: The space character has ASCII code 32, which is 20 in hexadecimal. Therefore: space = %20.
Example: The copyright symbol © is not ASCII. In UTF-8, it encodes to two bytes: 0xC2 and 0xA9. Therefore: © = %C2%A9 (three characters become six encoded characters).
The Essential Percent-Encoding Reference Table
| Character |
Encoded Form |
Context / Common Use |
| Space | %20 | Filenames, search queries, paths |
| ! | %21 | Exclamation in text |
| " | %22 | Quotation marks in queries |
| # | %23 | Hashtag in query string (not fragment) |
| $ | %24 | Dollar sign in query values |
| % | %25 | Literal percent sign in data |
| & | %26 | Ampersand in query values (not separator) |
| ' | %27 | Apostrophe in names, text |
| ( | %28 | Parenthesis in text |
| ) | %29 | Parenthesis in text |
| + | %2B | Plus sign in data (not space encoding) |
| , | %2C | Comma in data values |
| / | %2F | Forward slash in data (not path delimiter) |
| : | %3A | Colon in data (not scheme delimiter) |
| ; | %3B | Semicolon in data |
| = | %3D | Equals sign in data (not key=value separator) |
| ? | %3F | Question mark in data (not query start) |
| @ | %40 | At sign in data (email addresses in URLs) |
| [ | %5B | Square bracket in data |
| ] | %5D | Square bracket in data |
💡 Tip: The most important codes to memorize are: space = %20, & = %26, = = %3D, # = %23, and + = %2B. These five appear in the vast majority of real-world URL encoding situations.
Query String Encoding Rules
The query string is the portion of a URL that begins with a ? and contains key-value pairs separated by &:
https://example.com/search?q=machine+learning&category=technology&sort=relevance
In this URL:
q=machine+learning - the search term, where + represents a space (more on this below)
& - separator between parameters (if the data itself contains an ampersand, it must be encoded as %26)
= - separator between key and value (if the data contains an equals sign, it must be encoded as %3D)
When user input is incorporated into a query string, all special characters in the values must be encoded. If a user searches for "R&B music," the correct query string encoding is q=R%26B+music, not q=R&B music - the latter would be parsed as two separate parameters: q=R and B music (which is a malformed key without a value).
The + vs %20 Controversy for Spaces
This is a genuine source of confusion, even among experienced developers. Two different encoding conventions handle spaces in URLs:
- %20 - the RFC 3986 standard encoding for a literal space character. This is correct in all URL contexts: paths, query strings, fragments, and data values.
- + - an older convention from the HTML form encoding specification (application/x-www-form-urlencoded, defined in the HTML spec). In this context only, a
+ in a query string means "space." When a browser submits an HTML form via GET, it uses + for spaces in the query string.
The practical rule:
- In URL paths (before the
?), always use %20 for spaces. A + in a path is a literal plus sign, not a space.
- In HTML form-encoded query strings,
+ is conventionally used for spaces. Both + and %20 should work in modern query strings, but + is the form encoding standard.
- When in doubt or when writing code that generates URLs, use
%20 consistently - it's unambiguous in all contexts.
encodeURI vs encodeURIComponent in JavaScript
JavaScript provides two built-in functions for URL encoding, and choosing the wrong one is a common developer mistake:
encodeURI()
Encodes a complete URL. It does NOT encode characters that are valid URL syntax - it assumes the string is already a well-formed URL and only encodes characters that are genuinely unsafe (like spaces, non-ASCII characters, and a few others).
Characters it does NOT encode: A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #
encodeURI("https://example.com/search?q=hello world&lang=en")
// Returns: "https://example.com/search?q=hello%20world&lang=en"
// The & and = are preserved because they are valid URL syntax
encodeURIComponent()
Encodes a URL component - a single value that will be inserted into a URL. It encodes everything except unreserved characters (A-Z, a-z, 0-9, -, _, ., ~). This means it DOES encode &, =, /, ?, and # - characters that would break URL structure if they appeared unencoded in a query value.
encodeURIComponent("hello world")
// Returns: "hello%20world"
encodeURIComponent("R&B music")
// Returns: "R%26B%20music"
encodeURIComponent("price=50&sale=true")
// Returns: "price%3D50%26sale%3Dtrue"
When to Use Which
| Situation |
Use |
| Encoding a complete, pre-formed URL | encodeURI() |
| Encoding a query parameter value | encodeURIComponent() |
| Encoding a path segment that may contain slashes | encodeURIComponent() |
| Building a URL dynamically from user input | encodeURIComponent() for each value |
| Encoding a username or password in a URL | encodeURIComponent() |
⚠️ Warning: Encode user-provided values as URL components before inserting them into a URL, so characters such as & do not become unintended separators. URL encoding helps preserve structure; it is not, by itself, a security control or a substitute for validating what an application accepts.
When Everyday Users Encounter URL Encoding
URL encoding isn't just a developer concern. Regular web users encounter it in predictable situations:
- Search engine URLs: When you search for "machine learning" on Google, the URL becomes
?q=machine+learning or ?q=machine%20learning. When you search for "AT&T," the URL becomes ?q=AT%26T. This is normal encoding behavior.
- Broken links: If someone pastes a URL containing unencoded special characters into a document or sends it in an email, the characters may be stripped, modified, or misinterpreted by the receiving application. This is why URLs with spaces or special characters sometimes generate 404 errors when copy-pasted.
- Form submissions: When you fill out a web form and submit it, the browser encodes your input according to the form encoding spec. If the server fails to decode it correctly, form data can appear garbled - you might see %27 instead of an apostrophe in someone's name.
- Analytics and tracking: Marketing URLs with UTM parameters (like
&utm_source=newsletter) use URL encoding to pass campaign data through redirects and analytics systems. Incorrectly encoded UTM parameters cause tracking failures.
- API calls: REST APIs accept parameters via URLs. Developers who forget to encode query parameters when calling APIs will encounter unexpected behavior or errors when their data contains special characters.
Decoding: Reading URL-Encoded Strings
To read a URL-encoded string, simply reverse the process: replace each %XX sequence with the character corresponding to the hexadecimal value XX.
Example: caf%C3%A9 decodes as café (the é character is encoded as two bytes: C3 A9 in UTF-8)
Example: Hello%2C%20World%21 decodes as Hello, World!
In JavaScript, decodeURIComponent() and decodeURI() handle this (mirroring the encode functions). Most other programming languages have equivalent built-in functions.
Try It Free on Kinsad
Encode or decode any URL instantly - paste a URL or encoded string and get the clean result in one click. No installation required.
Use the URL Encoder/Decoder →
Frequently Asked Questions
Q: Why do some URLs use %20 for spaces while others use +?
Both are valid in query strings, but they come from different specifications. %20 is the RFC 3986 standard encoding for a literal space character. The + convention comes from the HTML form encoding spec (application/x-www-form-urlencoded) and only applies to query string values submitted by HTML forms. Modern URLs and APIs generally use %20 for consistency, but + is widely supported in query strings by web servers and frameworks. Never use + for spaces in URL paths - there it means a literal plus sign.
Q: What does %2F mean in a URL, and is it different from /?
Yes, significantly different. An unencoded / in a URL path is a path segment delimiter - it separates directory levels like /folder/subfolder/file. The encoded %2F is a literal slash character that should be treated as data, not a separator. For example, if a filename contains a slash (unusual but possible), encoding it as %2F prevents the server from interpreting it as a path separator. Some servers and proxies decode %2F before routing, which can cause security issues - this is actually documented in RFC 3986 as a known edge case.
Q: Are URL encoding and HTML encoding the same thing?
No. URL encoding (percent-encoding) converts characters to %XX format for safe inclusion in URLs. HTML encoding (HTML entity encoding) converts characters to &name; or &#XX; format for safe inclusion in HTML markup - for example, < becomes < and & becomes &. The two systems serve different purposes and apply in different contexts. A URL embedded in an HTML attribute may need both: the URL value percent-encoded for URL safety, and then the resulting string HTML-encoded for HTML safety.
Q: Do I need to encode numbers in URLs?
No. All decimal digits (0-9) are unreserved characters in RFC 3986 and never require encoding. You may freely include numbers anywhere in a URL - in paths, query strings, fragment identifiers - without encoding. The same applies to uppercase and lowercase English letters and the four symbols -, _, ., ~ (hyphen, underscore, period, tilde).