Developer Tools

What is URL Encoding and Why Is It Necessary?

URL encoding (percent encoding) rewrites unsafe characters as %XX byte codes so a URL means exactly one thing. Learn why a space becomes %20, which characters are reserved vs. unreserved per RFC 3986, and how to encode safely.

By Inventive HQ Team

URL encoding — formally called percent encoding — replaces characters that are unsafe or have special meaning in a URL with a percent sign followed by two hexadecimal digits representing the character's byte value. A space becomes %20, an ampersand becomes %26, and the letter é becomes %C3%A9. It exists so that a URL is unambiguous: the browser, server, or API reading it can always tell whether a character is part of your data or is a structural delimiter like ?, #, or &. The rules for which characters are safe come from RFC 3986, which sorts every character into unreserved (never encode), reserved (encode only when used as data), and everything else (always encode).

That is the summary an AI overview will give you. The part it can't give you is the mental model that makes URL encoding stop feeling arbitrary — why a space is illegal but a hyphen is fine, why the same character is sometimes encoded and sometimes not, and how to encode without introducing the double-encoding and UTF-8 bugs that break real links. This post is the fundamentals; the components of a URL, encoding international text, and the path-vs-query-string rules are covered in their own posts.

Loading interactive tool...

The core mechanic: one character in, %XX out

Percent encoding does exactly one thing, and understanding it removes most of the confusion. Take a character, look at the numeric value of each byte that represents it, write that value in two hexadecimal digits, and stick a % in front. That is the whole algorithm.

How a space character becomes %20 A space character is read as the ASCII code 32, converted to the hexadecimal value 20, and written as the encoded token percent-two-zero. Encoding one character: space to %20 character “␣” byte (decimal) 32 hex 0x20 encoded %20

The % sign means “an encoded byte follows”; the two hex digits are that byte's value.

Two consequences fall straight out of this. First, the % character itself has to be encoded (as %25) whenever you want a literal percent sign, otherwise a decoder would treat it as the start of an escape. Second, a character that takes more than one byte — every non-ASCII character in UTF-8 — becomes multiple %XX pairs, one per byte. The letter é (UTF-8 bytes C3 A9) becomes %C3%A9, not a single token.

Advertisement

Which characters get encoded: the RFC 3986 table

The single most useful thing to memorize is the character classification from RFC 3986. There are only three buckets, and the space between them explains almost every "why is this encoded and that isn't" question.

Character classMembers / examplesEncode it?RFC 3986 category
UnreservedAZ, az, 09, - _ . ~Never — always safe as-isunreserved
Reserved (delimiters): / ? # [ ] @ ! $ & ' ( ) * + , ; =Only when used as literal data, not as a delimiterreserved (gen-delims + sub-delims)
Other ASCII (unsafe)space, " < > % { } | \ ^ `Alwaysmust-encode
Non-ASCIIé, , 😀, any byte above 0x7FAlways — as UTF-8 bytes, one %XX per bytemust-encode

The interesting bucket is the middle one. Reserved characters are the URL's punctuation — ? separates the path from the query, & separates one query parameter from the next, / separates path segments. When you mean them as punctuation, leave them alone. When they appear inside your data, they must be encoded so they aren't mistaken for structure. A search for cats & dogs has to become ?q=cats%20%26%20dogs, because an unencoded & would start a second parameter and split your value in half.

Why an unencoded ampersand breaks a query The value cats and dogs, if left unencoded, is split into two parameters by the ampersand; encoding the ampersand as %26 keeps it as a single value. Encode reserved characters that appear in data Unencoded — the & splits the value: ?q=cats & dogs two parameters, not one Encoded — one intact value: ?q=cats%20%26%20dogs

Where URL encoding actually happens

You rarely encode by hand, and you shouldn't. Encoding runs silently every time you submit a web form, every time a search engine turns your query into a URL, and every time an API client attaches parameters to a request. The job of a developer is mostly to encode user input before it goes into a URL — because that input can contain anything.

Use your language's built-in functions rather than replacing characters yourself:

  • JavaScript: encodeURIComponent(value) for a single query value or path segment; encodeURI(url) for an already-assembled URL you must not break.
  • Python: urllib.parse.quote(value) for path segments; urllib.parse.quote_plus(value) for form-style query values (encodes spaces as +).
  • Command line: [System.Uri]::EscapeDataString('hello world') in PowerShell, or a one-line python3 -c 'import sys,urllib.parse;print(urllib.parse.quote(sys.stdin.read()))' on Linux/macOS.

These functions handle the edge cases — multi-byte UTF-8, the reserved-vs-unreserved distinction, the percent sign itself — that hand-written string replacement almost always gets wrong.

Space is a special case: %20 vs. +

One recurring confusion deserves its own note. A space can appear as either %20 or +, and both are correct in the right place. In the general URL syntax of RFC 3986, a space is encoded as %20. But in the older application/x-www-form-urlencoded format used for HTML form submissions, a space is encoded as +, and a literal plus sign is then written %2B. Modern code paths mostly standardize on %20, but if you see + in a query string it is almost certainly a form encoding, and a decoder for form data will turn it back into a space. When in doubt, %20 is the safe, universally understood form.

Encoding is not security

It is worth stating plainly because the mistake is common: URL encoding is for correctness, not protection. It guarantees a URL parses the way you intended; it does nothing to sanitize the meaning of the data inside.

Two failure modes matter. Double-encoding attacks exploit systems that decode more than once — a filter blocking ../ for directory traversal can miss %252e%252e%252f, which decodes first to %2e%2e%2f and then to ../. And context confusion: a value that is perfectly safe in a URL is still dangerous when later dropped into HTML (needs HTML encoding to stop XSS) or into SQL (needs parameterized queries). Always validate and sanitize input after decoding, and apply the encoding appropriate to each destination context rather than treating URL encoding as a security control.

Key takeaways

  • Percent encoding turns a character into % plus its byte value in two hex digits; a space is %20 because 32 decimal is 20 hex.
  • RFC 3986 sorts characters into unreserved (never encode), reserved (encode only when used as data), and everything else (always encode).
  • Non-ASCII characters are encoded as their UTF-8 bytes — one %XX pair per byte, so é is %C3%A9.
  • Use encodeURIComponent, urllib.parse.quote, or an equivalent built-in; never hand-roll encoding.
  • Encoding is about syntactic correctness, not security — still validate, sanitize, and re-encode for each context.

Ready to encode or decode a URL right now? Use our URL Encoder / Decoder tool for instant, accurate percent encoding with automatic UTF-8 handling — all processed client-side in your browser so your URLs never leave your device.

Frequently Asked Questions

What is URL encoding in simple terms?

URL encoding, also called percent encoding, is the process of replacing characters that are unsafe or reserved in a URL with a percent sign followed by two hexadecimal digits that represent the character's byte value. For example a space becomes %20 and an ampersand becomes %26. It exists so that every character in a URL is unambiguous — the software reading the URL can always tell the difference between a character that is part of the data and a character that is a structural delimiter like ? or &.

Why does a space become %20?

A literal space is not allowed inside a URL, and historically spaces got lost or mangled when URLs were copied into emails, printed, or wrapped across lines. The space character has the ASCII code 32, which is 20 in hexadecimal, so percent encoding writes it as %20 — the percent sign signals "an encoded byte follows" and 20 is that byte in hex. In the query string of an HTML form submission you may also see a space written as a plus sign (+), which is an older form-encoding convention.

What characters need to be URL encoded?

Everything except the "unreserved" set must be encoded when it appears as literal data. The unreserved characters — uppercase and lowercase letters, the digits 0-9, and the four symbols hyphen, underscore, period, and tilde — never need encoding. Reserved delimiter characters such as : / ? # [ ] @ ! $ & ' ( ) * + , ; = must be encoded whenever you want them treated as data rather than as structure. All other characters — the space, quotes, angle brackets, the percent sign itself, and every non-ASCII character — must always be encoded.

Is URL encoding the same as percent encoding?

Yes. "Percent encoding" is the formal name used in RFC 3986, the standard that defines URI syntax, because the mechanism uses the percent sign as an escape marker. "URL encoding" is the everyday name for the same thing. They are interchangeable terms for encoding a character as %XX.

What characters do NOT need to be URL encoded?

The unreserved characters defined by RFC 3986 are always safe and should never be encoded: the letters A-Z and a-z, the digits 0-9, and the four marks hyphen (-), underscore (_), period (.), and tilde (~). Encoding these anyway is technically valid but pointless, and some systems treat an unnecessarily encoded unreserved character as different from its plain form, which can cause subtle comparison bugs.

What is the difference between encodeURI and encodeURIComponent?

In JavaScript, encodeURI() is meant for encoding a whole URL, so it leaves the structural characters : / ? # & = alone. encodeURIComponent() is meant for a single piece of data you are inserting into a URL — a query value or a path segment — so it also encodes those delimiter characters. Use encodeURIComponent() for individual values (the common case) and encodeURI() only when encoding an already-assembled URL you must not break.

Does URL encoding make my application secure?

No. URL encoding is about syntactic correctness, not security. It ensures a URL parses the way you intend, but it does not sanitize input. Double-encoding attacks (for example %252e%252e for ..) can slip past naive filters, and a value that is safe in a URL can still be dangerous when later placed into HTML or SQL. Always validate and sanitize input after decoding, and apply the correct encoding for each context (URL, HTML, SQL) rather than relying on URL encoding as a defense.

How are international and non-ASCII characters encoded in a URL?

Non-ASCII characters are first converted to their UTF-8 byte sequence, and then each byte is percent-encoded individually. The letter é, for example, is two bytes in UTF-8 (0xC3 0xA9), so it becomes %C3%A9. An emoji or a CJK character can expand to three or four %XX pairs. This is why you should always use a proper encoding function rather than replacing characters by hand — getting the UTF-8 byte breakdown right manually is error-prone.

Why can the same URL be written with different encodings?

Because reserved characters only need encoding when they are used as data, not as delimiters, a URL can be "correct" in more than one form. A slash used as a path separator stays a slash, but a slash inside a filename must be written %2F. Two URLs that percent-encode different optional characters can point to the same resource, which is why systems that compare URLs should normalize them (decode unreserved characters, uppercase hex digits) before checking equality.

url encodingpercent encodingweb developmentUTF-8security