Spaces in URLs can be encoded as + (plus) or %20 (percent-twenty). They are not interchangeable. %20 works everywhere in a URL. Plus only works in form-encoded query strings. Using the wrong one causes broken links, failed API calls, and 404 errors.
This is one of the most common URL encoding mistakes, and the internet is full of conflicting advice. Here is the definitive answer, with the exact rules and when each applies.
| Encoding | Where It Works | Where It Breaks | Standard |
|---|---|---|---|
| %20 | ✓ URL path, query string, fragment — everywhere | Nowhere. %20 is universally valid. | RFC 3986 (URL standard) |
| + (plus) | ✓ Query string only (form data) | ✗ URL path — interpreted as literal "+" | HTML form spec (application/x-www-form-urlencoded) |
Rule of thumb: If you are unsure, use %20. It is always correct. The plus sign is a shorthand that only works in one specific context (form-encoded query strings), and using it elsewhere will break things.
The confusion exists because two different specifications define how spaces should be encoded:
application/x-www-form-urlencoded format, where spaces become + signs. This was a bandwidth optimization from the early web (+ is 1 byte; %20 is 3 bytes).The problem: when you look at a URL like ?search=hello+world, you cannot tell whether the + is a space (form-encoded) or a literal plus sign (RFC 3986). The answer depends on whether the server expects form encoding or standard URL encoding. This ambiguity has caused bugs in web applications for 30 years.
/api/users/John+Doe sends "John+Doe" (with a literal plus). /api/users/John%20Doe sends "John Doe" (with a space). Most APIs expect %20 in paths.?q=machine+learning works on Google because Google's server understands form encoding. But ?q=machine%20learning also works. Both are valid in query strings./files/my+report.pdf looks for a file literally named "my+report.pdf". /files/my%20report.pdf looks for "my report.pdf". Wrong encoding = 404./bucket/my+file.txt is a different object than /bucket/my%20file.txt. Mixing them up returns 404 or the wrong file.| Language | Default Function | Space Becomes | %20 Alternative |
|---|---|---|---|
| JavaScript | encodeURIComponent() | %20 | Already uses %20 by default |
| Python | urllib.parse.quote_plus() | + (plus) | Use urllib.parse.quote() for %20 |
| Java | URLEncoder.encode() | + (plus) | Chain .replace("+", "%20") after encoding |
| C# | HttpUtility.UrlEncode() | + (plus) | Use Uri.EscapeDataString() for %20 |
| PHP | urlencode() | + (plus) | Use rawurlencode() for %20 |
| Go | url.QueryEscape() | + (plus) | Use url.PathEscape() for %20 |
| Ruby | CGI.escape() | + (plus) | Use ERB::Util.url_encode() for %20 |
| Kotlin | URLEncoder.encode() | + (plus) | Chain .replace("+", "%20") after encoding |
| Swift | addingPercentEncoding() | %20 | Already uses %20 by default |
| Dart | Uri.encodeComponent() | %20 | Already uses %20 by default |
Notice: JavaScript, Swift, and Dart default to %20 (the correct RFC 3986 encoding). Java, C#, PHP, Go, and Ruby default to + (the HTML form encoding). Always check which function you are using.
This guide covers the standard behavior defined by RFC 3986 and the HTML form spec. Some legacy systems, older proxies, and non-standard APIs may handle space encoding differently. If you are integrating with a specific API, always check its documentation for encoding requirements — especially for authentication signatures, webhook payloads, and file storage paths where the difference between + and %20 can break things silently.
Encode your URLs right now — paste any text and get properly percent-encoded output.
Open URL Encoder Decoder