URL Encoding and Decoding Explained
Learn how percent-encoding works, when to use encodeURI or encodeURIComponent, why spaces become + or %20, and how UTF-8 represents text in URLs.
By TIG Tools editorial teamPublished October 25, 20265 min read
A URL can contain characters that have a special meaning, or that cannot be sent reliably as written. Percent-encoding represents those characters as % followed by a two-digit hexadecimal byte value, often using UTF-8 to turn text into bytes first. Use encodeURIComponent for a value that will go inside a URL component, and encodeURI only when encoding a complete URL whose structure is already in place.
What percent-encoding does
A URL has distinct parts: a scheme, a host, a path, a query, and sometimes a fragment. Characters such as /, ?, &, and # can separate those parts or their contents. If one of those characters is part of a value rather than structure, it must be encoded so it is not mistaken for a delimiter.
In percent-encoding, a byte is written as % followed by its hexadecimal value. For example, a space is commonly represented as %20, and an ampersand as %26. The percent sign itself is encoded as %25 when it is data. Hexadecimal letters in escapes can be uppercase or lowercase; both forms represent the same byte.
Percent-encoding is not encryption. It makes data safe to place in a URL context; anyone who can read the URL can decode it. Avoid putting passwords, access tokens, or other secrets in URLs, where they may be recorded in browser history, logs, or referrer data.
Reserved characters and URL structure
Some characters are called reserved because they have a defined role in URI syntax. Examples include / in a path, ? before a query, & between query parameters, = between a parameter name and value, and # before a fragment. A reserved character can still appear as data, but it may need percent-encoding in that context.
For example, suppose a search term is tea & coffee. In a query parameter, the ampersand must be treated as part of the value, not as the separator for another parameter. Encode the value as tea%20%26%20coffee, then place it in the URL:
https://example.com/search?q=tea%20%26%20coffee
The ? and = are URL structure. The space and ampersand belong to the value, so they are encoded. What needs encoding depends on where data is being placed; there is no single rule to encode every character in an entire URL indiscriminately.
encodeURI vs encodeURIComponent
JavaScript provides two commonly used functions for encoding URL text:
encodeURI(value)is intended for a complete URI. It preserves characters that can form its structure, including:,/,?,&,=, and#.encodeURIComponent(value)is intended for one component, such as a query parameter name or value. It encodes those structural characters so they remain part of the component rather than being treated as URL delimiters.
For the search-term example, use encodeURIComponent on the value:
const term = "tea & coffee";
const url = `https://example.com/search?q=${encodeURIComponent(term)}`;
console.log(url);
// https://example.com/search?q=tea%20%26%20coffee
A common mistake is to run encodeURIComponent on a complete URL. That encodes the colons and slashes too, so the result is no longer a normally structured URL. The reverse mistake—using encodeURI on an unencoded query value—can leave & or # active as delimiters. Encode each dynamic value as a component, then assemble the URL.
The JavaScript functions do not encode every punctuation mark. For example, encodeURIComponent leaves !, ', (, ), and * unescaped, in addition to letters, digits, and a few other characters. This is allowed by the function's encoding rules, though an application with stricter requirements may choose to encode some of those characters as well.
If you are inspecting a complete address or need to see its parts separately, the URL Parser can help identify the scheme, host, path, query, and fragment. To encode or decode text directly, use the URL Encoder / Decoder.
Why spaces appear as + or %20
%20 is the percent-encoded form of a space. A plus sign is not a universal substitute for a space in every URL. It represents a space in the form-encoding convention commonly used for query data (application/x-www-form-urlencoded). In that convention, a literal plus sign is encoded as %2B so it can be distinguished from a space.
This distinction matters when decoding. JavaScript's decodeURIComponent("a+b") returns a+b; it does not turn the plus into a space. By contrast, URLSearchParams uses form-style query handling, where a plus in serialized query data corresponds to a space:
const params = new URLSearchParams();
params.set("q", "tea & coffee");
console.log(params.toString());
// q=tea+%26+coffee
console.log(params.get("q"));
// tea & coffee
Use URLSearchParams when working with query parameters as parameters. Use encodeURIComponent when you specifically need to encode a single component yourself. Do not replace every + with a space without knowing the format: a plus might be literal data.
UTF-8 and non-ASCII text
Percent-encoding represents bytes, not whole characters directly. For text outside the basic ASCII range, the text is first encoded as bytes—typically UTF-8—and each byte is written as a %HH escape. One character can therefore become several escapes.
For example, é is encoded in UTF-8 as the two bytes C3 A9, so JavaScript produces caf%C3%A9 for café:
encodeURIComponent("café");
// "caf%C3%A9"
An emoji may use four UTF-8 bytes and therefore four percent escapes. When decoding, the bytes must be interpreted using the same character encoding, normally UTF-8. A string of escapes is not necessarily readable until those bytes are decoded as text.
Decoding safely and avoiding common errors
Decoding reverses percent-encoding when the escapes are valid. In JavaScript, decodeURIComponent decodes a component, while decodeURI is intended for a complete URI and preserves encoded forms of reserved characters where decoding could change the URI's structure.
A few practical checks help prevent bugs:
- Encode a value once, at the point where it is inserted into a URL. Encoding an already encoded value can turn
%20into%2520—a process called double encoding. - Decode only when you need the original value. A browser or server may already parse a URL component for you; decoding it again can change its meaning.
- Keep URL structure separate from data. Encode parameter names and values as components, not the separators between them.
- Handle malformed escapes. JavaScript decoding functions throw a
URIErrorif the input contains an invalid escape sequence or invalid UTF-8 encoding. - Treat decoded input as untrusted. Decoding changes representation, not safety; validate or escape the value for its next use, such as HTML or a database query.
Summary
- Percent-encoding writes bytes as
%HH; UTF-8 is used to represent non-ASCII text as bytes. - Use
encodeURIComponentfor a URL component andencodeURIfor a complete URL whose structure is already established. %20is the percent-encoded space;+means space in form-style query encoding, not in every URL context.- Encode dynamic values once, preserve delimiters between URL parts, and decode according to the format you are handling.
Try it now
Use the URL Encoder / Decoder for free, right in your browser. No sign-up, and your files stay on your device.
Open URL Encoder / Decoder