How Do You Properly Percent-Encode a URL or Query String?
Percent-encoding is how you make URL data safe by turning reserved or non-ASCII characters into %HH byte sequences. If you need to encode a path, query value, or full string without guessing which characters should survive, give the URL encoder a spin.
The key idea is simple: encode the data, not the structure. Query values, path segments, and fragment text are data; ?, &, =, and / are usually structure and should stay readable where they matter.
What percent-encoding actually changes
A URL is not plain text with extra decoration. It has syntax, and that syntax is picky. When a character could be mistaken for part of the URL structure, percent-encoding replaces it with a safe byte representation.
Common examples include spaces, #, %, &, =, and non-ASCII characters like é or 東京. In a query string, a literal space is usually encoded as %20. In some form submissions, + is used as a space placeholder, which is why URL encoding and application/x-www-form-urlencoded are related but not identical.
At the byte level, percent-encoding works on the encoded bytes of the text, usually UTF-8 bytes. That matters because é is not one byte in UTF-8; it becomes bytes that are then encoded individually. If you skip that step, you can end up with broken URLs that look fine until a server tries to decode them.
Encode data, not the whole URL
This is where people usually wreck their links. You do not take an entire URL like https://example.com/search?q=red & blue and blindly encode every character. If you do, the browser can no longer tell where the scheme ends, where the host begins, or what the query parameters are.
Instead, encode only the parts that are meant to be data. A safe mental model looks like this:
- Scheme: leave it alone, like
https. - Host: usually leave it alone, though international domains may need IDN handling.
- Path segments: encode each segment if it contains reserved characters.
- Query values: encode aggressively.
- Fragment text: encode if you are inserting arbitrary data.
So this is fine: /search?q=cat%20photos. This is not: %2Fsearch%3Fq%3Dcat%2520photos. The second one is a whole URL that got mangled into opaque noise.
If you need the broader anatomy of a URL first, our guide on what happens when you type a URL into your browser is a good companion piece. It helps explain why URL syntax is split across several layers before anything hits the server.
Path segments and query strings are not the same problem
Path segments are part of the route. Query strings are parameters. They are both URL components, but they do not share the same encoding assumptions.
In a path, the slash / separates segments, so if you want a literal slash inside a segment, it must be percent-encoded. For example, a file name of invoice/2025.pdf is not two folders and a file; it is one value that should become something like invoice%2F2025.pdf if your server expects it as a single segment.
Query strings are more forgiving in one sense and more dangerous in another. A value like red & blue must be encoded, or the & will split it into multiple parameters. Use name=red%20%26%20blue, not name=red & blue.
A practical rule: if you are building a path from user input, encode each path segment separately. If you are building ?key=value&key2=value2, encode each value, not the separators.
How browsers and servers decode the bytes
Decoding is the reverse operation. The parser sees %HH, turns each pair back into a byte, and then interprets the byte stream using the expected character encoding, usually UTF-8.
That is why malformed percent-encoding causes trouble. %2 is incomplete. %GG is invalid. Some parsers are strict and reject the input; others try to recover. Either way, relying on “it works in my browser” is a lousy debugging strategy.
Double-encoding is another classic failure mode. If your input already contains %20 and you encode it again, the percent sign becomes %25, producing %2520. When decoded once, that becomes %20, not a space. You now have a value that needs one more decode pass than you expected, which is how subtle bugs breed.
If you want to sanity-check the round trip, encode and then decode the same sample in a browser tool or in your app’s URL library. The output should return the original text, not a close approximation.
Practical rules that prevent bad URLs
There are a few habits that save time. They are boring, which is exactly why they work.
- Use UTF-8 before percent-encoding text.
- Encode user input as late as possible, right before it goes into the URL.
- Do not encode separators like
?,&, and=when they are part of URL structure. - Do encode literal reserved characters when they are meant as data.
- Never assume one decode pass will fix bad input.
In JavaScript, a lot of developers reach for encodeURIComponent() because it is designed for query values and path segments, not full URLs. By contrast, encodeURI() leaves URL structure characters alone. If that distinction feels fuzzy, our blog post on when to use encodeURIComponent covers the practical split.
When you are dealing with backend-generated links, also watch for frameworks that auto-encode values for you. Manual encoding on top of automatic encoding is one of the fastest ways to create %2520-style messes.
Where this shows up in real work
Percent-encoding is everywhere once you start looking. Search URLs need it. OAuth redirect URLs need it. Pre-signed links, tracking links, file download endpoints, and API requests with user-provided filters all depend on it.
It also shows up in less obvious places. A route parameter with an emoji, a filename in a download URL, or a filter like city=New York all need the same treatment. The browser and the server are not being difficult on purpose; they are just parsing symbols, and symbols have meaning.
The important part is consistency. If your app expects a raw string, decode it once at the edge and work with plain text inside your application. If your app emits a URL, encode exactly the components that need it and leave the rest alone.
A Worked Example
Say you need to build a search URL from the raw input cat & dog / 50%. The search term is data, so the whole value must be encoded before it is added to the query string.
Raw search term: cat & dog / 50%Encoded value: cat%20%26%20dog%20%2F%2050%25Final URL: https://example.com/search?q=cat%20%26%20dog%20%2F%2050%25Notice what changed. The space became %20, the ampersand became %26, the slash became %2F, and the percent sign became %25. The query separator ? and the parameter name q= stayed readable because they are part of the URL structure.
Now compare that with the mistake people make when they encode too much:
Wrong: https%3A%2F%2Fexample.com%2Fsearch%3Fq%3Dcat%2520%2526%2520dogThat string is no longer a usable URL in normal form. It is a percent-encoded version of the whole thing, including the protocol and slashes, which is almost never what you want.
Frequently Asked Questions
Should I use encodeURI or encodeURIComponent?
Use encodeURIComponent for query values and most user-provided URL parts, because it escapes more reserved characters. Use encodeURI only when you already have a full URL and want to preserve its structure. If you encode the entire URL with encodeURIComponent, you will break the separators.
Why is a space sometimes + and sometimes %20?
%20 is the standard percent-encoded space. + is commonly used in HTML form encoding inside query strings, where it represents a space during form submission. Many systems accept both, but they are not identical in every context.
Do I need to percent-encode the slash in a URL path?
Usually no, because / separates path segments. If the slash is part of the actual data, such as a filename or ID, then yes, encode it as %2F. The difference matters because servers may treat an unencoded slash as a path delimiter.
Can percent-encoding break international characters?
It can, if the text is encoded incorrectly before percent-encoding happens. The safe route is to convert the text to UTF-8 bytes first, then percent-encode those bytes. If your tool or code assumes the wrong character set, decoded text can come back garbled.
Wrapping Up
Percent-encoding is not hard, but it is easy to do in the wrong place. Keep the structure of the URL intact, encode only the data, and remember that non-ASCII text has to become bytes before it becomes %HH sequences.
If you are debugging a link, start by checking whether each component is encoded once, and only once. Then test a few awkward inputs: spaces, ampersands, slashes, Unicode, and percent signs. Those are the characters that usually expose bugs before users do.
When you want a quick sanity check, use this URL encoder tool and compare the output against the rules above. It is faster than staring at raw percent soup and pretending it looks fine.