Search code examples
javascriptlocal-storagemobile-safari

Storage events not firing in iOS Safari


I have two tabs in iOS Safari, both open to the same page. Both tabs have an event listener for the storage event on the window object, and both write to localstorage when the client clicks/taps/types.

In Internet Explorer the tab not being interacted with receives storage events, but not Safari (On Firefox and Chromium browsers I instead use the Broadcast Channel API for this). In addition, this code was previously tested on Safari (I'm afraid I cannot remember which version) and it worked.

I made sure no JavaScript errors are being thrown on the page, and that I wasn't testing in private browsing mode. Can anyone think of why storage events would simply stop firing?


Solution

  • At first I thought this was part of Tracking Prevention (which is still the case for a page and an iframe of the same page on a third-party page trying to communicate), but now I think this is actually a Safari bug.

    If you need to communicate cross-tab in Safari, use a Service Worker. My preferred cross-tab setup, in order of preferred to fallback to least-preferred fallback:

    1. Use a BroadcastChannel if supported, as this is literally the use case they were designed for.
    2. Use the message events of a Service Worker. Has slightly better support than a BroadcastChannel, but waking up a Service Worker regularly isn't great. Note that Service Workers don't work in Firefox Private Browsing mode, so it's a good thing Firefox supports BroadcastChannel.
    3. Use storage events. This is the only cross-tab communication method available in Internet Explorer, but if you don't need to support IE (lucky you) then feel free to not fall back this far. Note that this doesn't work in Safari Private Browsing mode (setting a localStorage item throws an error). Also note that there's an IE localStorage bug that means that the storage event's newValue property is actually the oldValue, so you need to delete the localStorage value after setting it to trigger it twice with the second time having the correct value.

    Also note that none of the above will let you communicate between a first-party and third-party context in Safari.