Putting a JSON object in a URL comes up more than it sounds like it should — a shareable link that encodes an app's full filter/sort state, a GraphQL query sent as a GET request, a complex search DSL passed to an API that only accepts query parameters. Here's the mechanism, and when reaching for it is (and isn't) the right call.
The mechanism
Serialize the object with JSON.stringify, then percent-encode the entire resulting string as one value — not each field individually, not the object's keys and values separately:
const filter = { status: "active", tags: ["js", "css"], page: 1 };
const json = JSON.stringify(filter);
// '{"status":"active","tags":["js","css"],"page":1}'
const encoded = encodeURIComponent(json);
// %7B%22status%22%3A%22active%22%2C%22tags%22%3A%5B%22js%22%2C%22css%22%5D%2C%22page%22%3A1%7D
const url = `/dashboard?filter=${encoded}`;Every {, }, ", :, ,, and [ ] gets escaped — none of them are safe left literal in a query value, and several (& if the JSON contained it, = if a value did) would actively corrupt the query string if left alone. Skipping this step is the one mistake that matters here: a raw, unencoded JSON string dropped into a URL either breaks outright or silently truncates at the first character the query parser misreads as structural.
Decoding it back
If you read the value with URLSearchParams (or most server-side query parsers), it's already been decoded once by the time you get it — you only need JSON.parse, not decodeURIComponent first:
const params = new URLSearchParams(location.search);
const filter = JSON.parse(params.get("filter"));
// { status: "active", tags: ["js", "css"], page: 1 }Calling decodeURIComponent on a value URLSearchParams already handed you decodes it a second time — harmless for most JSON content, but it'll throw or corrupt the result if any string inside the JSON happens to contain something that looks like a percent-escape sequence itself.
The size cost is real
The example above starts as 48 characters of JSON and comes out as 92 characters encoded — nearly double, mostly from every quote and brace expanding into a 3-character %XX sequence. For a small filter object that's fine; for anything larger it adds up fast, and URLs do have a practical length limit imposed by browsers and servers, not the JSON itself.
When flat query parameters are the better fit
If the object is flat — no nesting, just a handful of scalar fields and maybe an array — expressing it as ordinary repeated-key query parameters is usually more readable, more cacheable (some CDNs and proxies key on individual params), and shorter:
?status=active&tags=js&tags=css&page=1That's 38 characters against the JSON version's 92, for the same data — and it's directly debuggable in a browser address bar without decoding anything. Query Parameter Builder generates exactly this form straight from a JSON object, if that's the format you're starting from. Reach for full JSON-in-a-parameter instead when the shape genuinely doesn't flatten — nested objects, arrays of objects, or a schema that varies per request (a raw GraphQL variables object, for instance).
Common mistakes specific to this case
- Encoding the object's fields individually instead of the whole string. Percent-encoding happens after
JSON.stringify, on the complete serialized string — encoding each value separately and concatenating them doesn't produce valid JSON on the other end. - Forgetting
JSON.parsecan throw. A truncated or hand-edited URL is a realistic way for this value to arrive malformed — wrap the parse in a try/catch rather than assuming a URL parameter is trustworthy input. - Assuming order is preserved. Key order inside the JSON is fine (JSON objects preserve insertion order in every modern engine), but if this parameter sits alongside others in the query string, don't rely on where it falls relative to them — see How Query Parameters Work.
Try it yourself
Validate the JSON first with JSON Formatter, then build the query string — either the raw-JSON form or, for flat data, the repeated-key form — with Query Parameter Builder. To encode or decode a single value by hand, use URL Encode and URL Decode. All run entirely in your browser.