| Key | Value |
|---|
Paste a query string, or a whole URL, and see the parameters as
decoded key-value pairs. Repeated keys such as
tags[]=react&tags[]=astro are kept in full: one
table row per value, and an array in the JSON view, so no value
overwrites another.
| Key | Value |
|---|
A key that appears more than once, such as tags[]=a&tags[]=b, becomes an array in the JSON. Keys are kept as
written, so user[name] is not expanded
into a nested object.
Values are decoded with URLSearchParams, so
%20 and + both become a
space.
{
"q": "developer tools",
"category": "web",
"tags[]": [
"react",
"astro"
],
"sort": "newest",
"page": "1"
} const qs = "?q=hello+world&page=2&tags=react&tags=astro";
const params = new URLSearchParams(qs);
console.log(params.get("q")); // hello world
console.log(params.getAll("tags")); // [ 'react', 'astro' ]
console.log(params.has("page")); // true
// Plain object, last value wins for repeated keys
console.log(Object.fromEntries(params));
// Keep repeated keys as arrays (what the tool's JSON view does)
const result = {};
for (const key of new Set(params.keys())) {
const all = params.getAll(key);
result[key] = all.length === 1 ? all[0] : all;
}
console.log(JSON.stringify(result, null, 2));
// Modify and serialize back
params.set("page", "3");
params.delete("q");
console.log(params.toString()); // page=3&tags=react&tags=astro URLSearchParams decodes + as a space and ignores a leading ?. Every value is a string, so convert numbers yourself.
<?php
$qs = "q=hello+world&page=2&tags[]=react&tags[]=astro&user[name]=John";
// parse_str expands PHP-style brackets into nested arrays
parse_str($qs, $params);
print_r($params);
// In a web request the same data is already in $_GET
// echo $_GET["user"]["name"];
// Build a query string back from the array
echo http_build_query($params), PHP_EOL;
// q=hello+world&page=2&tags%5B0%5D=react&tags%5B1%5D=astro&user%5Bname%5D=John Without brackets, a repeated key keeps only the last value in PHP: a=1&a=2 gives ["a" => "2"].
from urllib.parse import parse_qs, parse_qsl, urlencode
qs = "q=hello+world&page=2&tags=react&tags=astro"
# Dict of lists: safe for repeated keys
print(parse_qs(qs))
# {'q': ['hello world'], 'page': ['2'], 'tags': ['react', 'astro']}
# List of (key, value) pairs in original order
print(parse_qsl(qs))
# Empty values are dropped unless you ask for them
print(parse_qs("a=&b=1", keep_blank_values=True))
# Serialize a dict back, expanding lists with doseq=True
print(urlencode({"page": 3, "tags": ["react", "astro"]}, doseq=True)) Django's request.GET and Flask's request.args wrap the same logic and offer getlist() for repeated keys.
RFC 3986 does not define the key=value&key=value format. The URL spec only says a query starts at ? and ends at #, and the structure inside comes from the HTML form spec. This is why + means a space in a query and nowhere else in a URL, and why frameworks disagree about repeated keys, empty values and bracket syntax.
Sort the keys before you build a URL that will be cached or signed. Servers and caches compare query strings as text, so ?a=1&b=2 and ?b=2&a=1 can end up as two cache entries for the same page.
This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
Either. If the input contains a question mark, the tool parses everything after it, so a full URL works as well as a bare q=hello&page=2.
Each occurrence gets its own row in the table, so tags[]=react&tags[]=astro shows two rows for tags[]. In the JSON view, the key holds an array of both values. Nothing is dropped.
No. Keys are shown exactly as written, matching the browser's URLSearchParams. PHP's parse_str() or the qs package in Node.js expand bracket keys into nested objects.
Yes. URLSearchParams decodes percent-encoded sequences, and a plus sign becomes a space, as in a form submission.
Yes. Open the JSON tab to see the parameters as an object, then click Copy. Keys that appear once hold a string, and repeated keys hold an array.
The URL parser breaks down the whole address, including host, path and fragment. For single values, encode and decode them directly.