URLs allow a surprisingly small set of characters. Letters, digits, and a handful of punctuation marks with specific structural jobs. Everything else has to be percent-encoded — replaced by a % followed by the hexadecimal value of each byte.
Skip that step and things break in ways that are genuinely hard to diagnose, because the URL usually still looks correct.
The three characters that cause most of the trouble
The space. A space is not legal in a URL at all. Some servers tolerate it, some truncate the address at that point, and some reject the request. Encoded, it becomes %20.
The ampersand. This is the one that produces the strangest bugs, because nothing appears to be wrong. In a query string, & separates one parameter from the next. Put an unencoded ampersand inside a parameter value and the server reads it as the start of a new parameter. A search for tools & utilities arrives as a search for tools, plus a mysterious parameter called utilities with no value.
The hash. A # marks the start of a fragment identifier, and everything after it is never sent to the server at all — it stays in the browser. So an unencoded hash inside a parameter does not corrupt the value; it silently deletes the rest of the URL from the server's point of view.
Two kinds of encoding, and choosing wrong is the real bug
This is where most encoding problems actually originate. There are two levels of aggressiveness, and they are not interchangeable.
Component encoding escapes everything that is not strictly safe, including the structural characters: &, =, ?, /, # and :. In JavaScript this is encodeURIComponent().
Full URL encoding leaves the structural characters alone and escapes only what is unsafe. In JavaScript this is encodeURI().
The rule: use component encoding for one value going inside a URL, and full encoding for a complete address you want to make valid.
What goes wrong when you pick the wrong one
Encode an entire URL with component encoding and every slash becomes %2F, producing an unusable string. This failure is obvious and gets fixed quickly.
The dangerous direction is the other one. Consider a redirect parameter:
https://example.com/login?redirect=https://example.com/account?tab=billing&view=full
Encoded at the full-URL level, the ampersand inside the redirect target survives. The server reads the outer URL as having two parameters: redirect (ending at the ampersand) and view. Your redirect target has lost half of itself, and a parameter you never intended to set has appeared on the outer request.
This is the mechanism behind a whole family of bugs, including some genuine security issues where an attacker crafts a value that injects extra parameters into the outer URL. Redirect targets, callback URLs and anything containing its own query string must be component-encoded.
%20 or a plus sign?
Both appear in the wild, and they come from different specifications.
%20 is the general percent-encoding for a space and is valid anywhere in a URL. The plus sign means a space only in application/x-www-form-urlencoded data — which is what an HTML form submits when it uses the GET method. That is why you see plus signs in search query strings so often.
The practical rule: %20 everywhere is always safe. A plus in a path segment is a literal plus character, never a space, so never use it there. In a query string either works, and you should match whatever the system you are integrating with expects.
Double encoding
If you have ever seen %2520 in a URL, you have seen double encoding.
Here is how it happens. %25 is the encoding of the % character itself. So when an already-encoded string gets encoded a second time, the % in %20 becomes %25, and the whole thing becomes %2520.
The usual cause is two systems in a chain each doing their job. An email platform wraps a link that a tag manager had already wrapped. A framework encodes a parameter that your own code had already encoded.
The symptom is a URL that arrives with visible %20 sequences in the page, or a parameter whose value contains percent signs where you expected spaces. The diagnosis is to look for %25. If it is there and you did not intend a literal percent sign in the data, something has encoded twice.
Non-Latin characters
Accented letters, Chinese characters and emoji are all legal in modern URLs — browsers display them correctly. But they are percent-encoded the instant the link is copied, so a readable address becomes a wall of escape sequences in every message that shares it.
For a query parameter this is usually fine, since nobody reads it. For the visible part of an address, transliterate to ASCII instead. It is one of the reasons well-formed slugs avoid accents entirely.
Practical debugging
When a link is behaving strangely, decode it and read the parameters as a list rather than squinting at a long string. Our URL Decoder breaks a query string into a table of names and values, which makes a duplicated parameter or a truncated redirect target obvious immediately. When you need to build a URL rather than read one, the URL Encoder has both modes clearly separated.
Summary
- Spaces, ampersands and hashes are the three characters that break URLs most often
- Component-encode individual values; full-encode complete addresses
- Redirect targets always need component encoding, or their parameters leak into the outer URL
%20is always safe for spaces; a plus means a space only in form-encoded data%25in a URL almost always means something encoded twice