snowplow-javascript-tracker
snowplow-javascript-tracker copied to clipboard
Investigate localStorage in multiple tabs
localStorage is shared between tabs, but the localStorage lock is restricted to a single tab. Can trackers operating in different tabs send duplicate events?
Possible solution: save the lock in localStorage.
Good thing to explore...
The biggest problem with putting a lock in localStorage is that the page could unload before it has a chance to release the lock. The lock will still be there if the user returns to the page and it will prevent events from being sent.
Hmm good point... I wonder if there is a way of identifying a tab uniquely which would be safer...
We might be able to do something like this:
http://balpha.de/2012/03/javascript-concurrency-and-locking-the-html5-localstorage/
Every time we acquire the localStorage lock, we set its value to the current time.
If we want to acquire the lock but it already exists, we check whether it is more than 10 seconds old.
If it is, then we conclude that the last tracker was unloaded before it was able to release the lock, and we acquire the lock.
Cool putting a TTL on the lock sounds like a good approach
I can make this bug appear if I change the tracker by wrapping the code which empties localStorage in a setTimeout of about 20ms.
This approach should prevent almost all duplicate events when multiple tabs are open simultaneously. But it could lead to lost events. Suppose a user opens an inbound link in a new tab, triggering a link click event in the current tab. If the link click isn't sent fast enough, the second tab won't be able to access localStorage, and will hold the page view event in memory. If the user leaves the second tab before triggering a second event there, the page view event will never make it to localStorage or the collector.
Another possible approach would be to treat tabs asymetrically. For example, say that only the first tab opened gets to use localStorage.
just passing through, but there's also sessionStorage which is per tab. might be helpful?
I thought about using sessionStorage, but the problem is that it gets cleared when the page session ends. The only reason the tracker uses localStorage is so that if events fail to send and the user leaves the page, the events will still exist when they return.
IndexedDB provides better concurrency primitives than localStorage. It isn't yet fully supported across all major browsers, but is worth investigating...