230

I have some values in my site which I want to clear when the browser is closed. I chose sessionStorage to store those values. When tab is closed they are indeed cleared, and kept if the user presses f5; But if the user opens some link in a different tab these values are unavailable.

How I can share sessionStorage values between all browser tabs with my application?

The use case: put a value in some storage, keep that value accessible in all browser tabs and clear it if all tabs are closed.

if (!sessionStorage.getItem(key)) {
    sessionStorage.setItem(key, defaultValue)
}
IronFlare
  • 2,287
  • 2
  • 17
  • 27
Vladimir Gordienko
  • 3,260
  • 3
  • 18
  • 25
  • 17
    It's weird to me that this got closed as a duplicate. Nominating for reopening. The other topic is about "how to communicate between multiple tabs", which sounds different, and also is different, when I start reading that other topic. – KajMagnus Feb 22 '19 at 09:13
  • 2
    It's possible use cookies ? which behave like that by default ? (but indeed - for get and set action they will demand further implementation) https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie – lingar May 13 '20 at 11:54
  • 1
    Apparently it sounds like at one point in time, sessionStorage was kept in sync across tabs: https://stackoverflow.com/questions/19867599/what-is-the-difference-between-localstorage-sessionstorage-session-and-cookies?rq=1#comment53655140_19869560 – Devin Rhode May 20 '21 at 19:23
  • If you are on this thread, you may also wonder at some point, what were the original use cases for sessionStorage? See: https://stackoverflow.com/questions/8498357/when-should-i-use-html5-sessionstorage – Devin Rhode May 20 '21 at 19:38

8 Answers8

188

You can use localStorage and its "storage" eventListener to transfer sessionStorage data from one tab to another.

This code would need to exist on ALL tabs. It should execute before your other scripts.

// transfers sessionStorage from one tab to another
var sessionStorage_transfer = function(event) {
  if(!event) { event = window.event; } // ie suq
  if(!event.newValue) return;          // do nothing if no value to work with
  if (event.key == 'getSessionStorage') {
    // another tab asked for the sessionStorage -> send it
    localStorage.setItem('sessionStorage', JSON.stringify(sessionStorage));
    // the other tab should now have it, so we're done with it.
    localStorage.removeItem('sessionStorage'); // <- could do short timeout as well.
  } else if (event.key == 'sessionStorage' && !sessionStorage.length) {
    // another tab sent data <- get it
    var data = JSON.parse(event.newValue);
    for (var key in data) {
      sessionStorage.setItem(key, data[key]);
    }
  }
};

// listen for changes to localStorage
if(window.addEventListener) {
  window.addEventListener("storage", sessionStorage_transfer, false);
} else {
  window.attachEvent("onstorage", sessionStorage_transfer);
};


// Ask other tabs for session storage (this is ONLY to trigger event)
if (!sessionStorage.length) {
  localStorage.setItem('getSessionStorage', 'foobar');
  localStorage.removeItem('getSessionStorage', 'foobar');
};

I tested this in chrome, ff, safari, ie 11, ie 10, ie9

This method "should work in IE8" but i could not test it as my IE was crashing every time i opened a tab.... any tab... on any website. (good ol IE) PS: you'll obviously need to include a JSON shim if you want IE8 support as well. :)

Credit goes to this full article: http://blog.guya.net/2015/06/12/sharing-sessionstorage-between-tabs-for-secure-multi-tab-authentication/

nawlbergs
  • 2,820
  • 1
  • 18
  • 11
  • 3
    How reliable is this solution? Since it is event based, is there any chance of missing an event? – vivek241 Oct 27 '15 at 09:48
  • 2
    Based on the answers here I created a library over localStorage and sessionStorage to simplify this. So now you just call storageManager.saveSyncedSessionData('data', 'key'); or storageManager.savePermanentData('data', 'key');, etc based on what you need. The full code is here: http://www.ebenmonney.com/blog/how-to-implement-remember-me-functionality-using-token-based-authentication-and-localstorage-in-a-web-application – adentum Dec 14 '16 at 11:18
  • @vivek241 The solution worked great for me when the JS file size was smaller and "the solution script" given above is loaded as first script in the page. When my JS file grew too larger, say 1000 or more lines, it suddenly stopped working and removed my cookies and specific localStorage data also. I am not sure this is a reliable or cross-browser solution that could be relied upon. So, rewrote all logic to solve the issue with cookie alone. – webblover Jan 18 '17 at 05:35
  • I confirm that this script(and library) doesn't work if you use them with complex javascript code. It does not show any error but It won't work on the new tab but it'll work if you refresh that new tab. My guess is that it must be something related to javascript asynchronous manner if your code can be refactored to wait the storage to finish their work(settimeout,Promise,etc...) it might work. – Persk Feb 10 '17 at 07:26
  • 5
    Wouldn't the event be triggered in all previously open tabs? – Dtipson Jun 05 '17 at 14:47
  • 1
    This example is not working in IE 11 and edge, can you please give a solution for that. – Nithinkumar CN Sep 17 '19 at 12:35
  • 2
    FWIW, this doesn't seem to work anymore (welcome, from the future ). `sessionStorage` is only triggering the 'storage' event across frames within a tab, so this (very clever) process won't work for tracking sessionStorage changes across tabs anymore. – alexbea Mar 02 '20 at 20:12
  • 14
    It's looking like `BroadcastChannel` is now a good tool for doing this. https://developers.google.com/web/updates/2016/09/broadcastchannel – alexbea Mar 02 '20 at 20:36
  • 6
    Isn't this a bad solution as all tabs who listen to changes in localStorage can read your sessionStorage? What is then the whole point of using SessionStorage, if you make yourself vulnerable this way? Like yes this works, but in some way your just using localstorage instead of session. – Riddim Mar 28 '20 at 14:45
  • 1
    It solves the problem however when you start to open multiple tabs, as for me three tabs all of my tabs hangs. – Cham Apr 02 '20 at 13:09
  • I think BroadcastChannel is the best way to solve this. There are also polyfills for BroadcastChannel (which happen to use localStorage under the hood) – Devin Rhode Mar 13 '21 at 00:56
  • I researched all the polyfills for BroadcastChannel and this seems to be the best option: https://github.com/pubkey/broadcast-channel – Devin Rhode Mar 13 '21 at 01:41
  • 1
    If the tab is on the same domain, would the session data be shared with all other tabs on the same domain? – Fritz Aug 15 '22 at 18:22
107

Using sessionStorage for this is not possible.

From the MDN Docs

Opening a page in a new tab or window will cause a new session to be initiated.

That means that you can't share between tabs, for this you should use localStorage

Henrik Andersson
  • 45,354
  • 16
  • 98
  • 92
  • 23
    Ok, i got it, but how i can clear localStorage when all browser tabs is closed? – Vladimir Gordienko Dec 02 '13 at 10:23
  • You could change the documents cookie to `path='/'` thus forcing it to clear when the browser window is closed. But for tabs, I have no idea right now. – Henrik Andersson Dec 02 '13 at 10:26
  • ok i will dig deeper and let you know if i found a solution, let think for now what it impossible)) – Vladimir Gordienko Dec 02 '13 at 10:35
  • @VladimirGordienko Did you find the solution to clear localStorage when all browser tabs are closed? – Anmol Gupta Mar 16 '16 at 11:33
  • 5
    @Anmol yes, but I cant provide any code already, it was far ago. this is ugly solution but it works for me perfectly. The key there is to keep tabsOpened counter in local storage and increase it on page load but decrease on page unload. So when page unload and tabsOpen == 1 its last tab and we can clear all stuff. There was some minor things that I was need to handle but cant remember what exactly. Hope it will help You! – Vladimir Gordienko Mar 16 '16 at 13:10
  • @VladimirGordienko, users may have tab opened within a different domain. – Md Toufiqul Islam Oct 02 '17 at 15:11
  • You would need to clear the session when the site is opened again, not when closed... unless you use `onunload` – doublejosh Nov 29 '17 at 04:21
  • 1
    @VladimirGordienko what if the unload event that deletes the `localStorage` data happens because someone navigates to a different domain, in the same tab. Seems to me this will incorrectly delete the `localStorage` data — the tab didn't get closed, and if the person navigates back, s/he would want the data again, right. Anyway, it's an interesting approach, didn't think of that :- ) – KajMagnus Feb 22 '19 at 09:08
  • 4
    If you right click on a tab in Chrome and click "duplicate" the `sessionStorage` is actually shared between the original and the duplicated tab. – Wilt Oct 29 '20 at 07:12
  • @Wilt How can one deal with the problems that arise when one duplicates the tab and receives inconsistency between the two tabs when one action, like switching an account, fails to update the duplicated tab? – Ian Steffy Dec 14 '21 at 09:49
  • @IanSteffy You can use [Storage events](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event) to keep track of changes in the storage where needed. – Wilt Dec 14 '21 at 16:03
  • 1
    @Wilt Clarification: The old sessionStorage is copied to the new tab, it's not in sync/shared after that. – Alex Jan 18 '23 at 11:34
  • @Alex That was a good comment... I should have not used the word "shared" in my comment, but "copied". – Wilt Jan 18 '23 at 13:29
16

Actually looking at other areas, if you open with _blank it keeps the sessionStorage as long as you're opening the tab when the parent is open:

In this link, there's a good jsfiddle to test it. sessionStorage on new window isn't empty, when following a link with target="_blank"

Community
  • 1
  • 1
Dan Parker
  • 823
  • 1
  • 11
  • 27
  • 3
    this does not work in Chrome since version 89 - https://developer.chrome.com/blog/deps-rems-89/ - Stop cloning sessionStorage for windows opened with noopener – michal.jakubeczy Jun 17 '21 at 13:51
13
  1. You can just use localStorage and remember the date it was first created in session cookie. When localStorage "session" is older than the value of cookie then you may clear the localStorage

    Cons of this is that someone can still read the data after the browser is closed so it's not a good solution if your data is private and confidental.

  2. You can store your data to localStorage for a couple of seconds and add event listener for a storage event. This way you will know when any of the tabs wrote something to the localStorage and you can copy its content to the sessionStorage, then just clear the localStorage

Community
  • 1
  • 1
Adassko
  • 5,201
  • 20
  • 37
6

I find the only way to share sessionStorage between tabs is window.open:

  • window.open('./page2.html','') open page2 with a new tab
  • window.open('./page2.html','height=100, width=100') open page2 with a new tab in a new window.

Page2 can get a copy of sessionStorage from page1, but the two sessionStorage object is independent of each other.

Dreamoon
  • 369
  • 5
  • 8
1

If you have a small amount of data you can use instead of sessionStorage a session cookie which remains active until the user closes their browser or clears their cookies. And it also preserves its value among multiple tabs.

A code to set a cookie

document.cookie = "cookiename=value; path=/";

By omitting expires we set a session cookie.

And you retrieve it like this:

function getCookie(name) {
  var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
  if (match) return match[2];
}

var value = getCookie('cookiename');
michal.jakubeczy
  • 8,221
  • 1
  • 59
  • 63
0

My solution to not having sessionStorage transferable over tabs was to create a localProfile and bang off this variable. If this variable is set but my sessionStorage variables arent go ahead and reinitialize them. When user logs out window closes destroy this localStorage variable

yardpenalty.com
  • 1,244
  • 2
  • 17
  • 32
-16

Here is a solution to prevent session shearing between browser tabs for a java application. This will work for IE (JSP/Servlet)

  1. In your first JSP page, onload event call a servlet (ajex call) to setup a "window.title" and event tracker in the session(just a integer variable to be set as 0 for first time)
  2. Make sure none of the other pages set a window.title
  3. All pages (including the first page) add a java script to check the window title once the page load is complete. if the title is not found then close the current page/tab(make sure to undo the "window.unload" function when this occurs)
  4. Set page window.onunload java script event(for all pages) to capture the page refresh event, if a page has been refreshed call the servlet to reset the event tracker.

1)first page JS

BODY onload="javascript:initPageLoad()"

function initPageLoad() {
    var xmlhttp;

    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else {
        // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }

    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {                           var serverResponse = xmlhttp.responseText;
            top.document.title=serverResponse;
        }
    };
                xmlhttp.open("GET", 'data.do', true);
    xmlhttp.send();

}

2)common JS for all pages

window.onunload = function() {
    var xmlhttp;
    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else {
        // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {             
            var serverResponse = xmlhttp.responseText;              
        }
    };

    xmlhttp.open("GET", 'data.do?reset=true', true);
    xmlhttp.send();
}

var readyStateCheckInterval = setInterval(function() {
if (document.readyState === "complete") {
    init();
    clearInterval(readyStateCheckInterval);
}}, 10);
function init(){ 
  if(document.title==""){   
  window.onunload=function() {};
  window.open('', '_self', ''); window.close();
  }
 }

3)web.xml - servlet mapping

<servlet-mapping>
<servlet-name>myAction</servlet-name>
<url-pattern>/data.do</url-pattern>     
</servlet-mapping>  
<servlet>
<servlet-name>myAction</servlet-name>
<servlet-class>xx.xxx.MyAction</servlet-class>
</servlet>

4)servlet code

public class MyAction extends HttpServlet {
 public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException {
    Integer sessionCount = (Integer) request.getSession().getAttribute(
            "sessionCount");
    PrintWriter out = response.getWriter();
    Boolean reset = Boolean.valueOf(request.getParameter("reset"));
    if (reset)
        sessionCount = new Integer(0);
    else {
        if (sessionCount == null || sessionCount == 0) {
            out.println("hello Title");
            sessionCount = new Integer(0);
        }
                          sessionCount++;
    }
    request.getSession().setAttribute("sessionCount", sessionCount);
    // Set standard HTTP/1.1 no-cache headers.
    response.setHeader("Cache-Control", "private, no-store, no-cache, must-                      revalidate");
    // Set standard HTTP/1.0 no-cache header.
    response.setHeader("Pragma", "no-cache");
} 
  }
DTB
  • 7
  • 1