You can resolve this without a database, but I wouldn't recommend it. Basically you have (user, localStorage) pairs and when a given user identifies himself/herself, his/her localStorage should be provided in a way. You can tell users to store their local storages at their own machine, but then they will have to copy it to other machines, which is labor-intensive and will never gain popularity. One could manually run a Javascript chunk in the console of their browser to make sure that localStorage has their data and having to copy the localStorage accross machines is only slightly easier than doing manually the whole thing.
You can put the localStorage information encoded into a URL, but besides the problem of URL length, which might become an issue and the ever present encoding problems, your whole localStorage can be monitored by a third party, having access to your router. I know you have said that the data is not sensitive, but I believe you that it's not sensitive yet. But once users will use this, if it's convenient, they will store sensitive data as well or, your clients might have such tasks for you, or even you might realize that you need to store data there which is not 100% public.
Besides these, in practice you will face very serious issues of synchronization, that is, it's all nice to make localStorage agnostic, but then, what's the real version? If you regularly work on 10 different sessions, then synchronizing the localStorages becomes a difficult problem. This means that the localStorage needs to be timestamped.
So, you will need a central place, a server to store the last saved localStorage version. If you are averted by databases for some unkown reasons, you can store localStorages inside files which identify the user, like
johndoe.json
and then, you will need to implement an export feature, which will send the current JSON of the user to the server and saves it into a file and an import feature, that will download the file stored for the user and ensure that localStorage gets updated accordingly. You can do the two together as well, implementing a synchronization.
This is simple so far, but what if the user already has some useful data inside his/her local localStorage and on the server as well? The simplest approach is to override one with another, but which one? If we are importing, then the local one is overrided, if exporting, then the one on the server is overrided, if we synchronize, then the older is overrided.
However, in some cases you want to merge two localStorages of the same user, so:
new elements
I believe that if an element is new, it should be known in some manner that it was created in this session, which is useful to know, because that means that on the other session that we are merging with, this new item was not removed and hence it's intuitive to add it.
element changes
If the same element is different in the two cases, then the newer version should prevail.
removed elements
The interesting case is when in one session it was removed and in the other it was updated. In this case I think the newer change should prevail.
However, despite of your best efforts, users might still mess up (and your software too) things, so backing up each session on your server makes sense.