URL Encoder / Decoder
Last updated: 23 August 2026
Reviewed by Gavin ยท Research and drafting assisted by AI
Percent-encode or percent-decode a string using the four JavaScript URL functions, or parse a query string into a key/value table. Live two-pane layout, runs entirely in your browser, no data leaves your device.
URL Encoder / Decoder
A URL encoder and decoder is a developer tool that converts between the human-readable form of a string and the percent-encoded form that is safe to transmit inside a Uniform Resource Locator. Almost every web request on the public internet depends on percent-encoding somewhere along its path: when a browser submits an HTML form, when a single-page app builds a query string for a fetch call, when a server reads a value from location.search, when an OAuth redirect bundles a callback URL into the redirect_uri parameter, when a CDN signs a URL with HMAC, and when an email link wraps a long URL to keep it on one line. This particular URL encoder / decoder implements the four standard JavaScript percent-encoding functions, encodeURIComponent, encodeURI, decodeURIComponent, and decodeURI, in a live two-pane layout, plus a separate query-string parser view that splits ?a=1&b=hello%20world into a key/value table with both raw and decoded columns. Everything runs entirely in your browser, so the strings you paste never leave your device.
The tool has two views. The default Encode / Decode view exposes all four JavaScript percent-encoding modes plus a copy button, a swap button that toggles between an encoder and its matching decoder, a clear button, and a small library of sample inputs. The Parse Query String view takes any query string (with or without the leading ?) and produces a five-column table showing the parameter index, the raw key, the raw value, the decoded key, and the decoded value, with malformed percent-sequences flagged per row.
How to Use the URL Encoder / Decoder
- Paste or type a string into the Input textarea on the left. The default sample is a complete search URL with a space and an ampersand already inside it.
- Pick a mode by clicking one of the four buttons:
encodeURIComponent,encodeURI,decodeURIComponent, ordecodeURI. The mode is described below the button row in muted text. - The result appears instantly in the Output textarea on the right. The output updates live as you type, so you can iterate without clicking a Run button.
- Click Copy output to put the result on your clipboard. The button briefly shows a green check mark to confirm the copy succeeded.
- Click โ Swap encode/decode to instantly toggle between an encoder and its matching decoder and move the current output into the input, handy for round-tripping.
- To parse a query string instead, click the Parse Query String tab above the input, then paste any
?a=1&b=2style string. The five-column table appears below.
The Encoding Rules
Percent-encoding is defined by RFC 3986, the IETF specification for URI Generic Syntax. RFC 3986 divides the characters allowed in a URI into three groups: unreserved characters that may appear unescaped anywhere, reserved characters that carry URL-syntactic meaning and may appear unescaped only where they serve that meaning, and everything else, which must be percent-encoded.
The unreserved set is exactly: the letters A through Z (uppercase and lowercase), the digits 0 through 9, the four punctuation characters - (hyphen), . (period), _ (underscore), and ~ (tilde). These eleven classes, fifty-two letters, ten digits, and four punctuation marks, never need to be encoded, no matter where they appear in a URL.
The reserved set is fourteen characters split into two sub-groups. The gen-delims (generic delimiters) are :, /, ?, #, [, ], and @. The sub-delims (sub-delimiters) are !, $, &, ', (, ), *, +, ,, ;, and =. A reserved character is allowed to appear unescaped only in the URI component where it carries its specific meaning, for example, / is allowed in the path, ? is allowed once to introduce the query, & is allowed inside the query to separate parameters, and # is allowed once to introduce the fragment. A reserved character appearing anywhere else must be percent-encoded as %XX where XX is the two-digit uppercase hexadecimal value of the byte.
Everything outside the unreserved and reserved sets, spaces, accented letters, emoji, non-Latin scripts, mathematical symbols, control characters, must always be percent-encoded. A space becomes %20, the Euro sign โฌ becomes the three-byte sequence %E2%82%AC, and the Chinese character ไธญ becomes %E4%B8%AD.
JavaScript's two encoder functions take different positions on the reserved set. encodeURIComponent is the strict function: it leaves unreserved characters alone and percent-encodes every reserved character. This makes it safe for building query-string values where any stray & or = would corrupt the surrounding structure. encodeURI is the permissive function: it leaves unreserved characters alone, leaves reserved characters alone (assuming they appear in a position where they carry meaning), and percent-encodes everything else. This makes it the right choice when you have a complete URL and only want to fix the spaces, accented letters, or other unsafe bytes in the path. decodeURIComponent and decodeURI are the inverses and will throw a URIError on any malformed percent-sequence, a stray % at the end of the string, %2 with only one hex digit, or %ZZ with non-hex characters.
Worked Examples
Example 1: A single space inside a query parameter.
Input: a b&c=d (mode encodeURIComponent)
Output: a%20b%26c%3Dd
Every space, ampersand, and equals sign is encoded, because all three are reserved characters that would otherwise break a query string.
Example 2: A full URL with a space in the path.
Input: http://x.com/a b (mode encodeURI)
Output: http://x.com/a%20b
Only the space is encoded. The ://, the / separators, the . in the domain, and the colon all stay unescaped because encodeURI knows they are part of the URL structure.
Example 3: The Euro sign, encoded and decoded.
Input: โฌ10 (mode encodeURIComponent)
Output: %E2%82%AC10
The Euro sign is U+20AC, which UTF-8 encodes to the three bytes 0xE2 0x82 0xAC, each percent-encoded separately. Feed that output back into decodeURIComponent and the round-trip recovers the original โฌ10 exactly.
Example 4: Characters that look like they should be encoded but are not.
Input: ~!*() (mode encodeURIComponent)
Output: ~!*()
The tilde, exclamation mark, asterisk, and parentheses are all part of the unreserved set (in the eyes of encodeURIComponent, which predates RFC 3986 by a few years and uses a slightly broader unreserved set). They pass through untouched.
Example 5: A query string with a plus sign.
Input: q=hello+world (mode decodeURIComponent)
Output: q=hello world
This is the application/x-www-form-urlencoded convention: a literal plus sign represents a space. JavaScript's decodeURIComponent does not apply this rule, it leaves + as a literal +. The Query String parser view in this tool applies the rule by calling decodeURIComponent after replacing + with a space, which matches how browsers and form parsers treat form-encoded data.
Example 6: A URL-safe alphabet boundary case.
Input: Hello? (mode encodeURIComponent)
Output: Hello%3F
A ? inside a parameter must be encoded because otherwise it would be read by the receiving server as the start of a new query. encodeURI would leave it alone, but encodeURIComponent correctly encodes it.
Where It Shows Up
Percent-encoding is not a corner-case feature; it is the plumbing of every modern web request. The most common place it appears is the application/x-www-form-urlencoded Content-Type, which is the default encoding for HTML form submissions and has been since the original Netscape forms in 1995. Every key and value in the form body is encoded with encodeURIComponent semantics, with the extra convention that + represents a space. A second common place is the query string of a GET request, where each parameter value is encoded with encodeURIComponent and then concatenated with & separators. A third is the redirect_uri parameter of OAuth 2.0, where the callback URL is encoded with encodeURIComponent so that its own query string and fragments do not interfere with the outer OAuth query string.
Outside the browser, percent-encoding shows up in server-side code that parses a URLSearchParams body, in shell scripts that build curl URLs, in Python's urllib.parse.quote and quote_plus (which mirror encodeURIComponent and the form encoder respectively), in Java's URLEncoder.encode, in Go's url.QueryEscape, and in any HTTP client library that accepts a query parameter as a map and serialises it for you. A CDN-signed URL is another place: AWS CloudFront, Cloudflare, and Fastly all use an HMAC over a canonical query string, and the canonical form requires every parameter value to be percent-encoded in the strict form. Getting the encoding wrong in any of these contexts typically produces a 400 Bad Request, a silent routing failure, or, in the worst case, a security vulnerability where user input crosses a syntactic boundary it was not supposed to.
Common Mistakes
The single most common mistake is reaching for encodeURI when encodeURIComponent was needed, or vice versa. If you are building a query-string parameter value, you almost always want encodeURIComponent, because any stray &, =, or # in the value will corrupt the surrounding query string. If you are cleaning up spaces and accented characters in a complete URL, you almost always want encodeURI, because encodeURIComponent would double-encode the ://, the / separators, and every other URL-syntax character. A useful rule of thumb: encode the value of each parameter separately, then concatenate, never encode the whole assembled URL in one shot.
The second most common mistake is double-encoding. If you call encodeURIComponent on a string that is already percent-encoded, the % characters themselves get encoded to %25, producing strings like %2520 for a space. Servers then read %2520 as a literal %20 and never decode it back to a space. The cure is to encode exactly once, at the boundary between "user data" and "URL".
The third most common mistake is forgetting the +-means-space convention. Inside a query string, the strings hello+world and hello%20world mean the same thing, both represent hello world. JavaScript's decodeURIComponent does not know this; it will leave + alone. The Query String parser view in this tool applies the rule for you, mirroring how browsers and form parsers handle application/x-www-form-urlencoded.
The fourth most common mistake is feeding an already-decoded string back into a decoder. A common bug is reading location.search in JavaScript and then calling decodeURIComponent on it, which will silently double-decode any % characters the browser has already expanded. The browser already decodes location.search for you; you almost always want to read the raw string and decode it once yourself, or use URLSearchParams directly.
Frequently Asked Questions
What is the difference between encodeURIComponent and encodeURI?
encodeURIComponent is the strict function: it escapes every character except A-Z a-z 0-9 - _ . ! ~ * ' ( ). Use it for individual query-string values, form-field values, and any place where a stray reserved character would break the surrounding URL. encodeURI is the permissive function: it escapes everything except the strict set above PLUS the URL-syntax characters ; / ? : @ & = + $ , #. Use it when you already have a complete URL and only want to fix the spaces or accented characters in it.
What does the % sign mean in a URL?
A % introduces a percent-encoded byte. The two characters that follow it must be hexadecimal digits (0-9 or A-F, case-insensitive) and together specify one byte of the decoded value. For example, %20 is the byte 0x20, which is a space in ASCII. %E2%82%AC is three bytes that UTF-8-decodes to the Euro sign โฌ. A % that is not followed by exactly two hex digits is malformed and causes decodeURIComponent to throw URIError: URI malformed.
Why does my decoded string show weird characters like รยฉ instead of รฉ?
You have a Latin-1 / UTF-8 mismatch. The bytes on the wire are UTF-8 (the modern standard) but the code on one side of the boundary is interpreting them as Latin-1 (or Windows-1252). The single character รฉ is 0xC3 0xA9 in UTF-8 and %C3%A9 percent-encoded. If a server decodes that to the two raw bytes 0xC3 and 0xA9 and a downstream component reads them as Latin-1, it sees รยฉ, the Latin-1 rendering of 0xC3 0xA9. The fix is to make sure every component along the path is using UTF-8: set the Content-Type charset header to utf-8, set <meta charset="utf-8"> on HTML pages, and pass encoding: 'utf8' to any Node.js file or stream operations.
Does the plus sign mean a space in a URL?
Only inside an application/x-www-form-urlencoded body or query string, where it is the original Netscape convention from 1995. Inside a path or fragment, + is a literal plus sign. JavaScript's decodeURIComponent does not apply the convention, so decodeURIComponent('hello+world') returns 'hello+world'. The Query String parser view in this tool applies the convention for you, mirroring how URLSearchParams and form parsers work.
Is my data sent to a server?
No. The URL Encoder / Decoder runs entirely in your browser. The encoding functions are built into JavaScript itself, the query-string parser is a few lines of pure JavaScript, and no network request is made. The strings you paste never leave your device, which matters when you are decoding URLs that contain session tokens, signed OAuth callbacks, or other values you would rather not upload to a third party.
Can I encode an entire URL at once?
You can, with encodeURI, and it will correctly encode the spaces and accented characters while leaving the URL syntax (://, /, :, ?, #) untouched. But you should almost never do that, because you lose the ability to safely nest one URL inside another's query string. The right pattern is: encode each parameter value with encodeURIComponent separately, build the query string with ? and & separators, and concatenate. If you need to embed a complete URL as a single parameter value, encode that one URL with encodeURIComponent.
What does URIError: URI malformed mean?
It means the input string contains an invalid percent-sequence. The four common causes are a stray % at the end of the string ("abc%"), a % followed by only one hex digit ("%2"), a % followed by two non-hex characters ("%ZZ"), and a % followed by a % ("%%20", the second % is not a valid hex digit). Fix the offending character and the decoder will succeed.
References
- RFC 3986, Uniform Resource Identifier (URI) Generic Syntax. The IETF specification that defines reserved and unreserved characters, the percent-encoding grammar, and the structure of URI components. https://www.rfc-editor.org/rfc/rfc3986
- WHATWG URL Living Standard, The browser-maintained specification that defines how URLs are parsed and serialised in modern web browsers, including the encoding rules used by
URL,URLSearchParams, and the navigation model. https://url.spec.whatwg.org/ - MDN Web Docs, encodeURIComponent. Documentation for the strict JavaScript encoder, including the exact set of characters it leaves unescaped and examples. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
- MDN Web Docs, encodeURI. Documentation for the permissive JavaScript encoder and the URL-syntax characters it preserves. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
- MDN Web Docs, URLSearchParams. The browser-native query-string parser, which uses
application/x-www-form-urlencodedsemantics including the+-means-space convention. https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams - ECMA-262, ECMAScript Language Specification, ยง25.6.2 URL Percent Encoding Functions. The formal specification for the four JavaScript encoder and decoder functions. https://tc39.es/ecma262/#sec-uri-handling-functions
Also try these free tools: