Same Mechanism, Two Names

Percent encoding and URL encoding describe the same thing: taking a character that is not safe to put directly into a URL and replacing it with a percent sign followed by two hex digits representing its byte value. "Percent encoding" is the precise name used in the governing specification, RFC 3986. "URL encoding" is the everyday name people reach for when the same mechanism is applied to a web address. If someone tells you the two are different, what they usually mean is one of the real, practical distinctions covered below, which are worth understanding on their own terms rather than as a correction to terminology. You can experiment with any of this directly in our URL encoder and decoder.

Byte by Byte: What Actually Happens

A URL is restricted to a small safe alphabet: uppercase and lowercase letters, digits, and a handful of punctuation marks. RFC 3986 calls this safe set the unreserved characters: A-Z, a-z, 0-9, and - _ . ~. Everything outside that set gets converted to one or more %XX sequences, where XX is the character's byte value written in hexadecimal. Some concrete conversions:

  • A space (byte value 32 decimal, 20 hex) becomes %20.
  • @ (byte value 64 decimal, 40 hex) becomes %40.
  • / (byte value 47 decimal, 2F hex) becomes %2F.
  • é becomes %C3%A9, two separate percent codes, because é is encoded as two bytes in UTF-8 (C3 and A9), and each byte gets its own percent sequence.

That last example matters more than it looks: percent encoding operates on raw bytes, not on "characters" as a human thinks of them. Any character outside the basic ASCII range turns into as many percent codes as it takes bytes to represent it in UTF-8, which is why encoded non-English text often looks noticeably longer than the original. The hex math behind those two-digit codes is walked through in our hex explainer, and the fuller character-by-character reference lives in our URL encoding guide.

Reserved vs Unreserved: Why Some Characters Are Special

RFC 3986 splits characters into two relevant groups. Unreserved characters (letters, digits, - _ . ~) never need encoding and are safe as literal data anywhere in a URL. Reserved characters (: / ? # [ ] @ ! $ & ' ( ) * + , ; =) carry structural meaning inside a URL, marking things like the path separator, the start of a query string, or the boundary between parameters. A reserved character used as structure stays unencoded. The exact same character used as literal data, say a question mark that is actually part of someone's search term rather than the start of a query string, must be percent encoded so it is not misread as structure. This reserved-versus-data distinction is the root of nearly every practical URL encoding bug.

Where This Actually Breaks Real Code

JavaScript exposes this exact distinction as two different functions, and mixing them up is one of the most common URL bugs in web development:

encodeURIencodeURIComponent
What it is forA complete URL you want to keep functionalA single value being inserted into a URL
Leaves untouchedStructural characters: : / ? & = #Encodes those characters too
Typical useA full address handed to a browser as-isA query parameter, path segment, or form field

The bug shows up when a full URL is embedded as the value of another URL's query parameter, for example a redirect link:

// Broken: encodeURI leaves the inner URL's & and ? unencoded
"/redirect?url=" + encodeURI("https://x.com/p?a=1&b=2")
// produces: /redirect?url=https://x.com/p?a=1&b=2
// the outer query string now reads a, b, and url as three separate parameters

// Correct: encodeURIComponent escapes the entire inner value
"/redirect?url=" + encodeURIComponent("https://x.com/p?a=1&b=2")
// produces: /redirect?url=https%3A%2F%2Fx.com%2Fp%3Fa%3D1%26b%3D2
// the outer query string correctly sees one parameter, url, with the full inner address as its value

The first version silently splits the inner URL's own query parameters into extra parameters on the outer URL, which typically breaks the redirect in a way that is easy to miss during testing and only surfaces once real user input with an ampersand or question mark hits it in production.

A simple rule that resolves almost every case: encoding a value that is going into a URL, use the component-level encoder that escapes everything. Encoding a full address you want to remain a working link, use the whole-URL encoder that leaves structure alone. Reaching for the wrong one is the single most common URL encoding mistake in real codebases.

The Space Character's Split Personality

Spaces have two valid encodings depending on exactly where they appear, and this is the second gotcha worth knowing on top of the encodeURI confusion. In the path portion of a URL and in most general contexts, a space is %20, following the standard percent encoding rule. But inside a query string that follows the older application/x-www-form-urlencoded convention, the convention used by traditional HTML form submissions, a space is instead represented as a literal plus sign, +. That is why a search for "new york" shows up as new+york in some URLs and new%20york in others: both are correct in their respective contexts, but only in their respective contexts. A decoder that assumes the wrong convention will turn a form-encoded + into a literal plus sign in the output instead of a space, or fail to recognize a %20 as one. Our URL encoder and decoder lets you paste a string and see both interpretations, which is the fastest way to spot which convention a given URL is actually using.

Four Places This Distinction Shows Up in Practice

  • Building links with dynamic values: any user-supplied search term, redirect target, or file name inserted into a URL needs component-level encoding, not whole-URL encoding.
  • Reading tracking and redirect links: decoding a long tracking URL reveals the real destination hiding inside it, a common practical use covered in our URL decode use cases post.
  • Debugging a broken link: a doubled sequence like %2520, a mismatched + where a %20 was expected, or a raw unencoded ampersand splitting a parameter are the three usual suspects.
  • Building against an API: query parameters carrying a nested URL, an access token, or a JSON blob almost always require full component-level encoding of that parameter's value.

Frequently Asked Questions

Is it technically correct to call this "URL encoding"?

Yes, for everyday use. It is the name almost everyone recognizes immediately. "Percent encoding" is the more precise term from the specification, and it is worth knowing because the same mechanism also shows up outside URLs, for example in data URIs. Saying "URL encode this" will not confuse anyone; the two names point at one mechanism.

Which characters always need to be encoded?

Spaces, any character outside basic ASCII, and the reserved structural characters whenever they appear as literal data rather than as structure: : / ? # [ ] @ ! $ & ' ( ) * + , ; =. Letters, digits, and - _ . ~ never need encoding under RFC 3986's unreserved set. The full reference table is in our URL encoding guide.

Why does é turn into two separate percent codes instead of one?

Because modern URLs encode text as UTF-8, and é is represented as two bytes in UTF-8 (hex C3 and A9), so it becomes %C3%A9. Any character outside the basic ASCII range typically spans multiple bytes and therefore multiple percent codes; that is expected behavior, not an encoding error.

What produces a broken %2520 in a URL?

Double encoding. A space first became %20, and then that entire string was encoded a second time, turning the percent sign itself into %25. Decoding once yields %20; decoding a second time yields the actual space. It is a sign that a value passed through two encoding steps somewhere in a pipeline when it should have passed through exactly one.

Does percent encoding provide any security benefit on its own?

Not by itself: it changes how data is represented for safe transport, it does not hide or encrypt anything, and an encoded string is trivially decoded by anyone. Applied correctly to untrusted values before they are inserted into a URL, it does play a role in preventing certain injection issues; applied incorrectly, missing encoding on user input is itself a common source of vulnerabilities. Correct, consistent component-level encoding of untrusted data is the actual safe habit, not the encoding mechanism alone.

Shoyeb Akter

Written by

Security Tools Developer and creator of 2FA Fast, a privacy-first browser-based authenticator and security tools platform.