dev

URL Encoding Explained: Why %20, +, and %2520 Aren't the Same Thing

Percent-encoding looks simple until a space turns into a plus sign, a URL gets encoded twice, or encodeURI and encodeURIComponent give you different results. Here's what's actually happening and how to avoid the common bugs.

👤FileConvy Team📅 August 3, 2026⏱️ 5 min read
#url encoder#percent encoding#encodeuricomponent#double encoding#query string#developer tools

A URL can only contain a small, fixed set of characters safely — letters, digits, and a handful of punctuation marks. Everything else (spaces, &, #, non-English characters, emoji) has to be represented some other way, or it either breaks the URL or gets silently misinterpreted. That "some other way" is percent-encoding, and most of the confusing bugs around it come from not knowing which of several slightly different encoding rules is being applied at any given moment.

What Percent-Encoding Actually Does

Percent-encoding replaces a character with % followed by its two-digit hex byte value. A space becomes %20 because 32 (the space character's ASCII code) is 20 in hex. An & becomes %26. Non-ASCII characters get encoded as their UTF-8 bytes, so é becomes %C3%A9 (two bytes, two %XX pairs).

The rules split characters into two groups:

  • Unreserved characters — letters, digits, -, ., _, ~ — never need encoding and are left alone.
  • Reserved characters: / ? # [ ] @ ! $ & ' ( ) * + , ; = — have special meaning within a URL (separating the path from the query, one parameter from another, and so on). Whether they need encoding depends on where they appear.

That last point is the source of most confusion: the same character is sometimes reserved and sometimes not, depending on context.

Why %20 and + Both Mean "Space"

This is the single most common source of confusion. There are two legitimate encodings for a space, from two different eras of the web:

  • %20 is the correct percent-encoding for a space anywhere in a URL — path, query string, anywhere.
  • + means "space" specifically inside a query string encoded as application/x-www-form-urlencoded — the format browsers have used for HTML form submissions since the 1990s.

The problem is that + is also a valid, literal character that can appear in data (a + in a phone number, for instance). If you decode a query string with a form-decoder, + becomes a space. If you decode the same string with a strict URI decoder, + stays a literal +. Get the wrong one and a search query like c++ either survives correctly or silently turns into c (two spaces). Neither decoder is "wrong" — they're answering different questions.

encodeURI vs encodeURIComponent: Not Interchangeable

JavaScript ships two built-in encoders that look similar but solve different problems:

  • encodeURIComponent() encodes almost everything except unreserved characters — including /, &, ?, and =. Use this for a single value you're about to insert into a URL, like a query parameter: encodeURIComponent("a&b")a%26b.
  • encodeURI() assumes you're encoding an entire URL that already has its structure in place, so it leaves /, &, ?, =, and : alone — encoding those would break the URL's structure. It only encodes things like spaces and non-ASCII characters.

Using encodeURI() on a single query parameter is a common bug: if the value itself contains & or =, they pass through unencoded and get misread as the start of a new parameter, corrupting the query string.

Double Encoding: The %2520 Bug

If you encode a string that's already encoded, the % from the first encoding pass gets encoded itself — % is %25 in hex — turning %20 into %2520. This happens constantly in real systems: a value gets encoded once when a form is submitted, then encoded again by a proxy, a redirect handler, or a second layer of application code that assumes it's still raw.

The symptom is always the same: what should decode to a clean value instead decodes to something with stray %25 sequences still in it, requiring a second decode pass to fix. The fix isn't a smarter decoder — it's finding where in the pipeline the value got encoded twice and removing one of those steps.

Quick FAQ

Should I use %20 or + for spaces? Use %20 unless you're specifically building a application/x-www-form-urlencoded query string (the default format for HTML GET forms), where + is conventional. When in doubt, %20 is unambiguous in every context.

Why does my decoded URL still have % signs in it? It's almost certainly double-encoded — decode it once more. If this keeps happening, the real fix is to find and remove the extra encoding step upstream rather than adding a permanent second decode.

Do I need to encode an entire URL, or just parts of it? Encode each dynamic value on its own with encodeURIComponent() before inserting it into the URL template. Encoding the whole finished URL at once is what causes structural characters like / and & to either get wrongly encoded or wrongly left alone.

Why do non-English characters turn into long %XX chains? Percent-encoding operates on UTF-8 bytes, not characters. Most non-ASCII characters take 2–4 bytes in UTF-8, so each one becomes 2–4 separate %XX groups.

Try It Yourself

Related Free Tools

SHARE THIS ARTICLE

TwitterLinkedIn
← Back to Blog

Related Articles

tutorial
Text to Speech Online, Explained: Why You Can't Download an MP3 (and How the Voices Actually Work)
6 min read
dev
Base64 Encoding Explained: Why Your File Just Got 33% Bigger
6 min read
dev
UUID v1 vs v4: Which One Should You Actually Use?
6 min read

Try FileConvy Free Tools

65+ tools — PDF, Image, Text, Dev & Calculators. No signup required.

Explore All Tools →