URLs may only contain a restricted set of characters, so everything else is written as a percent sign followed by two hex digits. The encoding itself is simple; nearly all the trouble comes from applying the wrong scope.
Component or whole URL — choose deliberately
Some characters carry structural meaning in a URL: the slash separates path segments, the question mark starts the query, the ampersand separates parameters. When you encode a single value, those characters must be escaped, or a value containing a slash will look like another path segment.
When you encode an entire address, they must not be escaped, or the URL stops being a URL. This is the whole difference between the two functions every language provides, and choosing the wrong one is the usual reason an encoded link breaks. Encode the value, then assemble the URL — not the other way round.
Why spaces are sometimes + and sometimes %20
Percent-encoding always writes a space as %20. The plus sign is a separate convention inherited from HTML form submissions, where application/x-www-form-urlencoded encodes spaces as + in the query string.
Both appear in the wild, so a decoder needs to handle each: + means a space inside a query string, but a literal plus sign inside a path. This is why a + in an email address so often survives a form and then arrives mangled — something decoded it in the wrong context.
Double encoding, and how to spot it
If you encode an already-encoded string, the percent signs themselves get encoded: %20 becomes %2520. A URL full of %25 is the signature of a value that went through encoding twice, usually because one layer of a stack encoded it and then a framework did it again.
The fix is never to add another decode on the end. Find the layer doing the extra encoding and remove it, otherwise a legitimate literal % in user input will break the moment someone types one.
In short
Encode values, assemble URLs. If you see %25 sprinkled through a link, something encoded it twice — fix the layer, not the symptom.
URL Encoder and Decoder
Percent-encode and decode URLs, and read any query string as a plain, already-decoded table.
Keep reading
UUID v4 vs v7: which one belongs in your database?
Random UUIDs scatter writes across an index. Time-ordered v7 fixes that, at the cost of revealing creation time — how to choose between them.
What makes a password strong (it isn't the symbols)
Why length beats complexity, what entropy in bits actually measures, and why the old advice about special characters made passwords worse.
MD5, SHA-1, SHA-256: which hash should you actually use?
What it means for a hash to be broken, why fast hashes are the wrong tool for passwords, and how to verify a downloaded file properly.