Pular para o conteúdo principal

Query String to JSON

This converter decodes a URL query string into structured JSON in your browser. Values are percent-decoded with + treated as a space, repeated keys become arrays, a[b]=c paths nest into objects, and empty values decode as null. Malformed percent-encoding is rejected with the position named. Nothing is uploaded.

Só local

A interface desta ferramenta está em inglês.

O guia abaixo está disponível apenas em inglês.

Query String to JSON explained

A query string looks like noise — ampersands, equals signs, percent escapes — but it is a record, and records deserve structure. This decoder turns one into a JSON object: keys from the left of each =, values decoded on the right, repeated keys collected into arrays and a[b]=c paths folded back into nested objects. It is the exact inverse of this site's JSON to Query String converter, so the pair round-trips.

Two conventions matter and both are honoured. The plus sign means a space — the application/x-www-form-urlencoded habit that virtually every form, browser and server still speaks — while %2B decodes to a real plus. And values stay strings: a query string carries no type information, so page=2 arrives as "2", honestly, rather than as a guess that a zip code would eventually punish.

Decoding happens entirely in this browser tab. The string is split and unescaped by in-page code; no request leaves the page, and the Content-Security-Policy forbids outbound connections outright. Verify it in the Network panel if you like — it stays silent, and that silence is the privacy claim holding.

Building the string you are about to parse is the job of the sibling JSON to Query String converter which emits the same a[b]=c convention this decoder reads.

Once the JSON output looks suspicious — a stray bracket, a missing quote — paste it into the JSON validator and the exact character at fault is pointed out.

How the decoding actually works

The converter accepts the query string with or without its leading ?. It splits on &, then splits each pair at its first =, so a key may only contain an equals sign when percent-encoded — which is exactly what the encoder on the other side of this pair does. Then, per pair:

  • Decode: key and value are percent-decoded as UTF-8, with + read as a space in values.
  • Nest: bracket segments in a key become nested objects — user[name] lands at {"user": {"name": ...}}, and a[user][city] nests two levels.
  • Collect: a key seen more than once becomes an array of its values in arrival order; a key seen exactly once stays a scalar.
  • Empty: a pair with an empty or missing value (token=, or a bare token with no =) decodes as null.

The conventions, input by input

The table below is the decoder's contract in miniature — every row is a documented rule rather than an accident of implementation:

Input pairDecoded JSON
page=2{"page": "2"} — a string, no type guessing
tag=navy&tag=math{"tag": ["navy", "math"]}
user[name]=Ada{"user": {"name": "Ada"}}
q=a%20b{"q": "a b"} — %20 decoded
q=a+b{"q": "a b"} — + is a space
q=a%2Bb{"q": "a+b"} — escaped plus survives
token={"token": null}

What the output looks like

The worked example below is the exact pair the Load sample button produces: the same string the JSON to Query String page emits, read back. Note that page stays "2" and admin stays "true" — strings, because the URL said nothing about types. Consumers that want numbers cast deliberately at the edge of the program, with the schema in hand, instead of trusting an inference that a leading-zero zip code would break.

Refusals, not guesses

Malformed escapes are where decoding tools quietly corrupt data, so this converter refuses instead of improvising. A percent sign must begin a valid escape — two hexadecimal digits forming valid UTF-8 — and anything else gets a named error:

  • %ZZ or %2 — not hexadecimal, so the error names the key and the character position rather than emitting a literal percent or a dropped byte.
  • %FF standing alone — hexadecimally valid but not valid UTF-8, so it is rejected rather than delivered as mojibake downstream.
  • A trailing bare % at the end of the string — a truncated escape, rejected with its position so the source can be fixed rather than guessed at.

Frequently asked questions

Does decoding a query string upload it anywhere?

No. The string is split and decoded by in-page JavaScript inside this browser tab. The page defines no API endpoint to send data to, and its Content-Security-Policy blocks outbound requests, so there is nothing to upload to even if the code tried. Open DevTools, convert a string, and the Network panel stays empty — the claim verifies itself in one glance.

Why are all the values strings?

Because a query string carries no type information: page=2 is the two characters 2 as far as the URL is concerned. The decoder refuses to guess, so 2 stays "2" and true stays "true" — the same policy the encoder side follows. Cast where the schema is known instead; a bare 02134 zip code silently becoming the number 2134 is the classic reason inference hurts.

What does + mean when decoding?

A space. That is the application/x-www-form-urlencoded convention browsers and servers have spoken for decades, and query strings in the wild overwhelmingly originate from forms. A literal plus must arrive percent-encoded as %2B — the encoder on this site emits it that way, and both spellings decode identically here. The reverse direction is consistent: spaces go out as %20, pluses as %2B.

How are repeated keys handled?

A key that appears more than once becomes an array of its values in the order they arrived: tag=navy&tag=math yields {"tag": ["navy", "math"]}. A key seen exactly once stays a scalar. This matches how Rack and Node's qs parser behave, and it is the precise inverse of this site's encoder, which repeats the key once per array element.

How does the a[b]=c notation decode?

Bracket segments become nested objects: user[name]=Ada decodes to {"user": {"name": "Ada"}}, and a[user][city] nests two levels deep. Numeric segments stay string keys — a[0] becomes the key "0" — because inventing arrays from indices is a guess this decoder declines to make. Both literal brackets and their %5B/%5D escaped forms are accepted, since encoders differ on that point.

What happens to a pair with no value?

An empty value — token=, or a bare token with no = at all — decodes as null rather than an empty string. That is the deliberate inverse of this site's JSON to Query String converter, which emits null as an empty value, so null survives the round trip intact. If you need to distinguish an empty string from an absent value, a query string fundamentally cannot express the difference.