Encoding a Query String

A query string is built by encoding each key and value separately, then joining them, not by encoding the whole string at once. Learn the correct construction order.

ZERO UPLOAD · ALL LOCAL
  1. The tool opens in DECODE mode. Paste a percent-encoded URL or string into the input field.
  2. The decoded output appears instantly. If the input contains a query string, each parameter is parsed into an editable table.
  3. Edit any value in the parameter table to see the rebuilt encoded query string update in real time.
  4. Switch to ENCODE mode to convert text to three encoding variants: encodeURIComponent, encodeURI, and form encoding with + for spaces.
  5. Click Copy next to any result to copy it to your clipboard.

Worked examples for this use case

Correct: encode each value first

Before
key: user name, value: A&B
After
user%20name=A%26B

Each piece is encoded before the = and & are added, so the delimiters stay literal.

Incorrect: encode the whole string

Before
user name=A&B
After
user%20name%3DA%26B

Encoding the assembled string escapes the intended = and & delimiters, producing an unusable single blob.

Using URLSearchParams to build it safely

Before
new URLSearchParams({q: 'cats & dogs'})
After
q=cats+%26+dogs

The built-in class encodes each value correctly and joins them with the right delimiters automatically.

Editing a value in the parameter table

Before
q=cats
After
q=cats%26dogs

Typing "cats&dogs" into the decoded value field rebuilds the query string with the ampersand safely escaped.

INPUT

DECODED OUTPUT
ENCODED OUTPUT
encodeURIComponent
encodeURI
Form encoding (+)

How to Encode a Query String Correctly, Key by Key

Building a query string correctly means encoding the parts before you join them, never the joined string afterward. A query string is a sequence of key-value pairs, each pair joined by = and separated from the next by &. Those two characters, = and &, are structural delimiters under RFC 39861, so if a key or a value contains one, encoding the whole assembled string at the end is already too late: the delimiter has already done its damage to the structure before you got the chance to escape it.

The correct order is to percent-encode each key and each value independently with encodeURIComponent, then join the encoded pieces with = and &. Consequently, any & or = that was part of your data survives as %26 or %3D, while the delimiters you intentionally added stay literal.2 CapyToolkit's decode mode parses a query string into an editable table using exactly this per-value logic, which is the same discipline you want in your own code.

Why encoding the whole query string is wrong

Encoding an assembled query string treats your delimiters as if they were data, which breaks the string in the opposite direction from not encoding at all. If you build q=cats&page=2 first and then run the entire thing through encodeURIComponent, every & and = gets escaped, including the ones you deliberately placed to separate parameters.3

Consequently, the result, q%3Dcats%26page%3D2, is no longer a valid query string at all; it is a single opaque blob that a server reads as one meaningless value. The mistake is subtle because the function did exactly what it promises, escaping every character outside the unreserved set, but it was applied at the wrong stage. The fix is to change when you encode, not which function you use: encode each piece before assembly, never the assembled whole. Once you internalize that rule, the same discipline applies whether you are building a query string by hand, through a templating helper, or inside a shared library used across a whole codebase.

What happens when a server reads the blob

When a parser receives q%3Dcats%26page%3D2, it sees no literal = or &, so it cannot split the string into separate parameters. The most common outcome is that the server drops the query entirely or treats it as a single malformed key with an empty value. Seeing this in a browser history or analytics report is confusing because the string still looks like a URL at a glance. The only reliable way to recognize it is to decode the full string yourself and notice that the structural characters have been replaced by percent-escapes.

Correcting the mistake is straightforward once you understand the order: identify the original keys and values, encode each one separately with encodeURIComponent, and then rejoin them with literal = and &. This kind of query-string data recovery after an encoding mistake usually takes seconds and immediately turns the unusable blob back into a parsable query string. Maintaining the encode-then-join habit prevents the entire class of bug from recurring.

The correct build order: encode, then join

Building a correct query string follows a fixed three-step order, and skipping any of those steps is the most common reason URLs arrive at servers with the wrong number of parameters or with values that appear empty. First, take each key and value as plain, un-encoded text. Second, run encodeURIComponent on the key and on the value separately, before either of them ever touches a = or & that was meant to structure the query.4

Joining the encoded pieces

Third, join each encoded key to its encoded value with a literal =, and join each resulting pair to the next with a literal &. Following this order, a key user name and value A&B become user%20name=A%26B, with the delimiter characters you added remaining literal while the data character inside the value stays safely escaped. Furthermore, this is exactly what URLSearchParams does internally when you call its .toString() method5, so reaching for that built-in class instead of hand-assembling strings removes the chance of getting the order wrong. Sticking to this three-step order also makes code review easier, since a reviewer can check each step in isolation rather than reasoning about one long concatenation.

Rebuilding and editing with the tool

The CapyToolkit decoder mirrors this per-value discipline whenever you paste a URL containing a query string. Each parameter is split into its decoded key and decoded value and shown in an editable table, so you see the human-readable data rather than the escaped form behind a mask of percent-sign sequences. That split avoids the mental overhead of decoding percent-escapes while simultaneously tracing where one parameter ends and the next begins, especially in long query strings with many keys.

Editing a value without breaking the rest

Building on this, editing any value in that table triggers a rebuild that re-encodes only the changed value with encodeURIComponent and reassembles the full query string with & and = in their correct, literal positions. This means you can safely insert a value containing an ampersand, a plus sign, or non-ASCII text directly into the table, and the rebuilt query string below will encode exactly that value correctly, without you needing to manually escape anything or risk encoding the whole string by mistake. That per-field rebuild is the same discipline described above, made visible so you can watch the delimiters stay literal while only the data changes.

When to use this

Use this construction order whenever you build a query string manually in code, debug an API request that arrives with the wrong number of parameters, or need to insert a value that might contain &, =, or non-ASCII characters. When in doubt, prefer a built-in serializer like URLSearchParams over string concatenation, and use CapyToolkit to verify that a query string you already have decodes into the parameters you expect. Treating query-string construction as a per-value operation rather than a single string edit is the habit that prevents this entire class of bug from recurring.

Examples

Correct: encode each value first

Before
key: user name, value: A&B
After
user%20name=A%26B

Each piece is encoded before the = and & are added, so the delimiters stay literal.

Incorrect: encode the whole string

Before
user name=A&B
After
user%20name%3DA%26B

Encoding the assembled string escapes the intended = and & delimiters, producing an unusable single blob.

Using URLSearchParams to build it safely

Before
new URLSearchParams({q: 'cats & dogs'})
After
q=cats+%26+dogs

The built-in class encodes each value correctly and joins them with the right delimiters automatically.

Editing a value in the parameter table

Before
q=cats
After
q=cats%26dogs

Typing "cats&dogs" into the decoded value field rebuilds the query string with the ampersand safely escaped.

Sources
  1. 1.

    IETF, "Reserved Characters," RFC 3986 Section 2.2, datatracker.ietf.org, January 2005. https://datatracker.ietf.org/doc/html/rfc3986#section-2.2

  2. 2.

    WHATWG, "URL Standard," url.spec.whatwg.org, accessed July 2026. https://url.spec.whatwg.org/

  3. 3.

    Mozilla Developer Network, "encodeURIComponent()," developer.mozilla.org, accessed July 2026. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

  4. 4.

    ECMA, "encodeURIComponent (uriComponent)," ECMAScript 2027 Language Specification, Section 18.2.6.1, tc39.es, July 2026. https://tc39.es/ecma262/#sec-encodeuricomponent-uricomponent

  5. 5.

    Mozilla Developer Network, "URLSearchParams," developer.mozilla.org, accessed July 2026. https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

FAQ