Persist state via URL query parameters while avoiding long strings

  • I’m persisting some state in my application via URL query parameters.
  • The state is used to determine filters/sorts applied to a table.
  • The issue is that the resulting string can get too long.
  • I’m trying to find reliable ways to shorten the string but keep all the information I need.
  • Security isn’t a concern – I don’t care if the user can decode the compressed value.
  • The parameters I’m adding could be up to 200 characters (after calling encodeURIComponent).

Below is some additional information about the data structure I’m trying to save, and some things I’ve tried.

I’m thinking that compressing the string in this way isn’t going to work, but I’m not sure. So, overall, here are my questions:

  1. Is it possible to compress a string of up to/around 200 characters to something significantly shorter (30-40 characters?), and still be able to reliably decompress it?
  2. Is there a better approach to persisting this kind of information via URL than trying to compress it?

This is part of a React/Next app, but I’m not looking to use an external state manager like Redux.


Data structure

Below is the data I’m attempting to save to the URL. About 4 different parameters to later be retrieved and used.

{
    // Length of the arrays may be about 1-5 elements each.
    property1: string[],
    property2: string[],
    // Length of the strings may be up to about 10 characters each.
    property3: string,
    property4: string,
}

It’s possible there may be more/less parameters in the future, with varying data types. I’m looking for a generalized solution, but it’s never going to be wildly different than this.


Attempt 1: Convert to base64

Using btoa and atob, I tried converting the string to base64 before saving it to the URL.

The resulting string is at least around the same length, if not longer, so it’s not suitable.


Attempt 2: Compress the string

Using pako, which is a JS port of zlib, I tried compressing the string before saving it to the URL.

const compressed = pako.deflate(encodeURIComponent(JSON.stringify(objectToStore)))

deflate returns a Uint8Array. When converted to a string, this ends up much longer than a base64-encoded string or just the raw string itself.

I also attempted to convert the Uint8Array to base64 or even hexadecimal, but it’s still too long.

I’ve seen other compression libraries but generally they’d probably have the same results.


Attempt 3: Cryptographic solution

This wasn’t tenable because, while a cryptographically-secure hash could probably be significantly shorter, I wouldn’t be able to decode it from what I understood after reading many other questions along these lines.

An example of what I was hoping would work is the library object-hash, but since it’s intended for cryptographic solutions, it’s intentionally one-way only.


Attempt 4: Disguise the URL

I’m using Next, so I have the option to disguise/decorate the URL to hide these parameters via the as parameter of the Next/router:

router.replace(`domain.com/page?sort=${hashedObj}`, 'domain.com/page')

This allows me to hide the URL query parameters from view, but it’s not usable because if the page is refreshed/reloaded, those hidden parameters are no longer part of the URL. So it unfortunately defeats the whole purpose of having them there in the first place.


I’m not entirely sure how to approach it beyond this point. I could do something like save this data to local storage, or even to a server, but I’d rather avoid that since persisting it via the URL would be so much easier. My implementation to persist to the URL already works, I just need to find a way to make the resulting URL somewhat shorter for presentation purposes.