Query String to JSON Converter
A query string is easy to recognize but surprisingly awkward to inspect once it contains encoded characters, empty values, repeated filters, and application-specific flags.
Run — free
This query string to JSON converter turns that compact transport format into a structured object you can read, copy, compare, or feed into a debugging workflow. It decodes percent escapes as UTF-8, interprets plus signs as spaces, keeps blank values visible, and represents repeated parameter names as arrays in their original order. The transformation is deterministic and local to the parser, making the result suitable for request analysis, test fixtures, logs, and developer tools.
Turn compact request parameters into an inspectable object
Query strings are designed for transport, not comfortable reading. A browser or client may send a search term, several selected tags, an empty optional field, and a language-specific location in one dense line. Paste the portion after the URL path into the converter, with or without its leading question mark, and the result separates every parameter into a JSON property. A parameter written without an equals sign is retained with an empty string value, just like a parameter explicitly followed by an empty equals sign. Empty segments between ampersands are ignored because they do not contain a parameter. This makes the output useful when comparing a request against application state: values are visible, blanks are not silently discarded, and counts show both the number of distinct keys and the number of parsed pairs. The parser does not contact the destination server or infer business types, so values such as true, 42, and null remain strings instead of being changed through guesswork. That predictable behavior makes the converted JSON safe to use as a debugging representation of what the query actually carried.
Understand decoding and repeated-key behavior
Each key and value is decoded independently using the conventional form-query rules used by web requests. A plus sign becomes a space, while percent escapes such as %20 and multi-byte UTF-8 sequences become their intended characters. The equals sign is special only at its first occurrence within a pair, so a value may contain additional equals signs without being split again. Repeated keys are preserved rather than overwritten: the first occurrence starts as a string, the second promotes that property to an array, and later occurrences are appended in encounter order. For example, tag=sale&tag=new becomes a tag array containing sale followed by new. This is especially helpful for filters, checkbox groups, and frameworks that serialize multiple selections under one field name. Invalid percent escapes are rejected with an input error instead of being partially decoded, and encoded byte sequences that are not valid UTF-8 are rejected as well. Strict failure is important during debugging because a plausible-looking partial result can conceal a malformed request. The returned counts provide an additional quick check: pair_count includes repeated occurrences, while key_count reports distinct decoded property names.
Use the result in testing, logging, and request diagnosis
The converted object works well wherever a raw query needs to be understood before code acts on it. During API development, paste a failing request's query string and compare the decoded JSON with the parameters your route expected. In automated tests, convert representative strings into stable fixtures and assert that repeated filters, international text, plus signs, and blank fields arrive in the intended shape. When reviewing logs, the structured form is easier to scan and diff than a long encoded line, particularly when the same key occurs several times. The converter deliberately avoids schema coercion: if your application expects a number, boolean, date, or nested convention such as brackets, apply that application's validation after parsing. This boundary prevents a generic inspection tool from inventing meanings the sender never declared. It also treats property names safely as data, including names that resemble JavaScript object internals, so debugging unusual inputs does not alter the parser's behavior. Use the browser version for quick interactive checks, or call the API for $0.002 when a pipeline, test runner, support tool, or observability workflow needs the same deterministic conversion repeatedly.
What you can do with it
Debug an API request
Decode the exact query sent by a client and compare its keys, blank values, and repeated filters with the route contract.
Create stable test fixtures
Turn representative query strings into deterministic JSON expectations for integration tests and regression suites.
Inspect encoded log data
Make percent-encoded request parameters readable before investigating search behavior, redirects, or tracking integrations.
FAQ
What does the converter cost?
The browser tool is free to use. API requests use the published base price of $0.002.
Can I include the leading question mark?
Yes. The input may begin with a question mark, or it may contain only the characters that follow it.
How are repeated parameter names represented?
A key that appears once has a string value. When it repeats, its values become an array in their original order.
Does it decode plus signs and percent encoding?
Yes. Plus signs become spaces, and valid percent-encoded bytes are decoded as UTF-8 in both keys and values.
Does it convert numbers and booleans to JSON types?
No. Query parameters are returned as strings so the converter does not guess a schema or change the sender's data.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/dev/query-string-to-json \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"?search=blue+shoes&tag=sale&tag=new&city=S%C3%A3o+Paulo&empty="}'const res = await fetch("https://api.kit.forhosting.com/dev/query-string-to-json", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "?search=blue+shoes&tag=sale&tag=new&city=S%C3%A3o+Paulo&empty="
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev/query-string-to-json",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "?search=blue+shoes&tag=sale&tag=new&city=S%C3%A3o+Paulo&empty="
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev/query-string-to-json", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"?search=blue+shoes&tag=sale&tag=new&city=S%C3%A3o+Paulo&empty="}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"?search=blue+shoes&tag=sale&tag=new&city=S%C3%A3o+Paulo&empty="}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev/query-string-to-json", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "?search=blue+shoes&tag=sale&tag=new&city=S%C3%A3o+Paulo&empty="
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev.query_string_to_json",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |