154

What's the most reliable way to have JavaScript communicate between tabs/windows of the same browser? For example, when Tab 2 starts audio playback, Tab 1 somehow knows about this and can pause its player.

I'm building a site with a music player... so at the moment if you open two tabs to the site, you could start music on both. This is obviously bad, so I'm trying to find a solution.

5
  • 2
    Auto-playing the audio is bad no matter what. Why not just let the users click a "play" button, and manually pause the other tab if they hit this situation? Commented Nov 2, 2010 at 15:39
  • 9
    There's no autoplay. But it would be nice if the user didn't have to manually pause the other tab. Youtube does this for example (with flash) Commented Nov 2, 2010 at 15:54
  • stackoverflow.com/questions/19125823/… Commented Oct 3, 2013 at 22:24
  • There are other options, like shared webworkers and localstore storage event... Commented Oct 3, 2013 at 23:11
  • See this library Commented Jul 29, 2018 at 11:50

10 Answers 10

149

For a more modern solution check out https://stackoverflow.com/a/12514384/270274

Quote:

I'm sticking to the shared local data solution mentioned in the question using localStorage. It seems to be the best solution in terms of reliability, performance, and browser compatibility.

localStorage is implemented in all modern browsers.

The storage event fires when other tabs makes changes to localStorage. This is quite handy for communication purposes.

Reference:
http://dev.w3.org/html5/webstorage/
http://dev.w3.org/html5/webstorage/#the-storage-event

Sign up to request clarification or add additional context in comments.

5 Comments

This is better than the accepted solution. This doesn't require you to check constantly for new informations, doesn't have a delay and enables you to receive all events.
I have issues with localStorage on IE11, see this post (i faced point# 3) blogs.msdn.com/b/ieinternals/archive/2009/09/16/… so the cockie soliution is better (for IE at least). Also i tried to disable cockies but it still working (this is on IE 11).
This solve a lot of issues (are is wider implemented than BroadcastChannel), but be careful that you will have some surprises if user opens 2 "sender" tabs in the same browser: having 1 common communication channel might raise up some surprises
93

Update to a modern solution, leaving the old one below for historical reasons.

You can use Broadcast Channel API to send and receive messages https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API

// Connection to a broadcast channel
const bc = new BroadcastChannel('test_channel');

// Example of sending of a very simple message
// It doesn't have to be a string, it could be a JS object
bc.postMessage('This is a test message.');

To receive the message:

// A handler that only logs the event to the console:
bc.onmessage = function (ev) {
  console.log(ev);
}

and to close the channel:

// Disconnect the channel
bc.close();

THIS IS HISTORICAL OLD WAY TO DO IT, USE THE METHOD ABOVE FOR MODERN BROWSERS!

You can communicate between browser windows (and tabs too) using cookies.

Here is an example of sender and receiver:

sender.html

<h1>Sender</h1>

<p>Type into the text box below and watch the text 
   appear automatically in the receiver.</p>

<form name="sender">
<input type="text" name="message" size="30" value="">
<input type="reset" value="Clean">
</form>

<script type="text/javascript"><!--
function setCookie(value) {
    document.cookie = "cookie-msg-test=" + value + "; path=/";
    return true;
}
function updateMessage() {
    var t = document.forms['sender'].elements['message'];
    setCookie(t.value);
    setTimeout(updateMessage, 100);
}
updateMessage();
//--></script>

receiver.html:

<h1>Receiver</h1>

<p>Watch the text appear in the text box below as you type it in the sender.</p>

<form name="receiver">
<input type="text" name="message" size="30" value="" readonly disabled>
</form>

<script type="text/javascript"><!--
function getCookie() {
    var cname = "cookie-msg-test=";
    var ca = document.cookie.split(';');
    for (var i=0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(cname) == 0) {
            return c.substring(cname.length, c.length);
        }
    }
    return null;
}
function updateMessage() {
    var text = getCookie();
    document.forms['receiver'].elements['message'].value = text;
    setTimeout(updateMessage, 100);
}
updateMessage();
//--></script>

12 Comments

I thought of something like this too, but was hoping for a better solution than cookies/setTimeout. This might just be the only solution however. Thx
Don't pass a string to setTimeout - you're using eval by doing that. Instead, pass the function in directly with setTimeout(updateMessage, 100)
I would also recommend using setInterval()
I have issues with localStorage on IE11, see this post (i faced point# 3) blogs.msdn.com/b/ieinternals/archive/2009/09/16/… so the cockie soliution is better (for IE at least). Also i tried to disable cockies but it still working (this is on IE 11, IE 10, IE 9).
Tomáš Zato, be aware the answer is from 2010 - when HTML5 was not supported by all the browsers and the share of IE6 and IE7 was pretty high. There are better solutions now.
|
16

I don't think you need cookies. Each document's JavaScript code can access the other document elements. So you can use them directly to share data.

Your first window w1 opens w2 and save the reference

var w2 = window.open(...)

In w2 you can access w1 using the opener property of window.

13 Comments

USING COOKIES? Eat them and enjoy! There is a MUCH easier way! Just access a var of the other window. Got a value var in w1, access it from w2 whit window.opener.value !
Let's say that the user opens them all. Any similar solution in that case?
Just so everyone knows, this is answer is wrong, as @Ferdinak already tried to say. You don't have a reference to a tab the user opens.
Interesting is irrelevant. This is a Q&A site first and foremost. People come to this page to look for answers to the asker's question. If you want to share something interesting, you should consider writing a new wiki-style question.
@jonas.ninja IMO the question was not 100% clear on how the tabs are opened, so this is a perfectly valid answer even if it's not a universal one.
|
15

There is also an experimental technology called Broadcast Channel API that is designed specifically for communication between different browser contexts with same origin. You can post messages to and recieve messages from another browser context without having a reference to it:

var channel = new BroadcastChannel("foo");
channel.onmessage = function( e ) {
  // Process messages from other contexts.
};
// Send message to other listening contexts.
channel.postMessage({ value: 42, type: "bar"});

Obviously this is experiental technology and is not supported accross all browsers yet.

2 Comments

It's no longer experimental, even tho Edge might have not implemented it (it's marked ? in MDN)
Edge has it now.
15

You can do this via the local storage API. Note that this works only between two tabs. You can't put both sender and receiver on the same page:

On the sender page:

localStorage.setItem("someKey", "someValue");

On the receiver page:

    $(document).ready(function () {

        window.addEventListener('storage', storageEventHandler, false);

        function storageEventHandler(evt) {
            alert("storage event called key: " + evt.key);
        }
    });

3 Comments

I was going to use this method until I found out that the webbrowser control does not fire the "storage" event handler method. Not sure why. Bug perhaps.
Thanks for this solution. Made my day. It didn't work with file:/// protocol but works with a valid domain. Another similar demo html5demos.com/storage-events
You don't need to wait for DOM readiness in order to access localStorage
13

Below window(w1) opens another window(w2). Any window can send/receive message to/from another window. So we should ideally verify that the message originated from the window(w2) we opened.

In w1

var w2 = window.open("abc.do");
window.addEventListener("message", function(event){
    console.log(event.data);
});

In w2(abc.do)

window.opener.postMessage("Hi! I'm w2", "*");

2 Comments

Does it works on all browsers?
@StepanYakovenko support for browsers: developer.mozilla.org/en-US/docs/Web/API/Window/…
10

Communicating between different JavaScript execution context was supported even before HTML5 if the documents was of the same origin.

If not or you have no reference to the other Window object, then you could use the new postMessage API introduced with HTML5. I elaborated a bit on both approaches in this Stack Overflow answer.

1 Comment

postMessage API is not designed for that stackoverflow.com/a/1100416/470117 You need the reference of targeted window to post a message for that specific window
9

You can communicate between windows (tabbed or not) if they have a child-parent relationship.

Create and update a child window:

<html>
<head>
<title>Cross window test script</title>
<script>
var i = 0;
function open_and_run() {
    var w2 = window.open("", "winCounter"); 
    var myVar=setInterval(function(){myTimer(w2)},1000);
}

function myTimer(w2) {
    i++;
    w2.document.body.innerHTML="<center><h1>" + i + "</h1><p></center>";
}
</script>
</head>
<body>
Click to open a new window 
<button onclick="open_and_run();">Test This!</button>    
</body>
</html>

Child windows can use the parent object to communicate with the parent that spawned it, so you could control the music player from either window.

See it in action here: https://jsbin.com/cokipotajo/edit?html,js,output

2 Comments

One problem here is, that we can not (without being hacky) share a link to our synced view...
@yckart There are so many ways to do this but the most common way I've seen is to send the string to an input box in the other window. You can make an event listener for a change of value. Example: stackoverflow.com/questions/9994120/… . I think it would be better to just call a javascript function in the other window, passing it the URL. E.g., <a href="javascript:window.parent.mySendURL(url)"> from the child window or <a href="javascript:myChildWindow.mySendURL(url)"> from the parent window.
2

I found a different way using HTML5 localstorage. I've created a library with events like API:

sysend.on('foo', function(message) {
    console.log(message);
});
var input = document.getElementsByTagName('input')[0];
document.getElementsByTagName('button')[0].onclick = function() {
    sysend.broadcast('foo', {message: input.value});
};

https://github.com/jcubic/sysend.js

It will send messages to all other pages, but not to the current one.

EDIT:

The library in the newest version also supports broadcast channel communication, but still, it works in IE11 that only supports local Storage. It also supports cross-origin communication (different domains) but a little bit of code.

The latest API also supports the emit function that executes events also on the same page.

Even latest version, also suport managing the windows, send message to particular window or get list of widows/tabs.

2 Comments

Can you add a link to this library?
-1

With Flash you can communicate between any window, any browser (yes, from Firefox to Internet Explorer at runtime) ...any form of instance of Flash (Shockwave or ActiveX).

5 Comments

Question was not about Flash.
This won't work in most mobile situations.
To be fair, Flash runs "a form of" Javascript just as the OP requested
How does it work? What is the mechanism? Wouldn't the browser prevent it from working? Does it go through some server on the Internet?
OK, he has left the building. Can somebody else chime it?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.