Communication between browser tabs/windows using JavaScript [duplicate]
Asked Answered
F

10

153

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.

Fachan answered 2/11, 2010 at 15:36 Comment(5)
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?Israelisraeli
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)Fachan
#19126323Gracious
There are other options, like shared webworkers and localstore storage event...Gracious
See this libraryDiabolize
A
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>
Abysmal answered 2/11, 2010 at 15:48 Comment(12)
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. ThxFachan
what kind of player are you using? If it's a flash player, you can do stuff with flash that might be more elegant.Abysmal
Don't pass a string to setTimeout - you're using eval by doing that. Instead, pass the function in directly with setTimeout(updateMessage, 100)Nullity
changed the setTimeout as per Yi suggestion.Abysmal
I open sourced a project based on this answer, in case anyone is interested: github.com/jeremyharris/local_connectionEndothermic
I can see that setTimeout every 100 ms is consuming the javascript specially in Chrome when you open more than 4 browser tabs.Feather
I would also recommend using setInterval()Upspring
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).Fraud
This only works if both tabs have same host.Trochlear
This is so bad answer I can't even...Dependency
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.Abysmal
That's now a very bad usage of cookies: 1) they are uselessly sent to server 2) value must be escaped when put in the cookie 3) having 2 "sender" tabs opened will be a mess 4) you are limited by cookie size 5) you are not applying Hollywood principle (heavy useless computations) 6) attacker can mess with this client-side only communication from the server side if they manage to alter cookies (=architecture is leaking). So see BroadcastChannel insteadKayne
E
150

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

Equinoctial answered 20/9, 2012 at 14:11 Comment(5)
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.Waziristan
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).Fraud
Good demo page - html5demos.com/storage-events#view-sourceLorettelorgnette
@Anas: Link is dead. New URL: blogs.msdn.microsoft.com/ieinternals/2009/09/15/…Carburetor
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 surprisesKayne
A
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>
Abysmal answered 2/11, 2010 at 15:48 Comment(12)
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. ThxFachan
what kind of player are you using? If it's a flash player, you can do stuff with flash that might be more elegant.Abysmal
Don't pass a string to setTimeout - you're using eval by doing that. Instead, pass the function in directly with setTimeout(updateMessage, 100)Nullity
changed the setTimeout as per Yi suggestion.Abysmal
I open sourced a project based on this answer, in case anyone is interested: github.com/jeremyharris/local_connectionEndothermic
I can see that setTimeout every 100 ms is consuming the javascript specially in Chrome when you open more than 4 browser tabs.Feather
I would also recommend using setInterval()Upspring
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).Fraud
This only works if both tabs have same host.Trochlear
This is so bad answer I can't even...Dependency
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.Abysmal
That's now a very bad usage of cookies: 1) they are uselessly sent to server 2) value must be escaped when put in the cookie 3) having 2 "sender" tabs opened will be a mess 4) you are limited by cookie size 5) you are not applying Hollywood principle (heavy useless computations) 6) attacker can mess with this client-side only communication from the server side if they manage to alter cookies (=architecture is leaking). So see BroadcastChannel insteadKayne
U
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.

Unmentionable answered 7/2, 2012 at 16:50 Comment(13)
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 !Unmentionable
Let's say that the user opens them all. Any similar solution in that case?Fostoria
I think that you may open as many windows you want and use this solution. The reference to any new window must be registered somewhere. The reference to the parent window is always available. I don't see any limitation so far. @FardinakUnmentionable
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.Lavinialavinie
@DDS: you are right, as an answer this is wrong, but it seems to be interesting, so I let it there. Using localStorage I think is the right solution.Unmentionable
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.Sattler
a little bit different question, is it possible for the child window to call a method from parent window? by parent window I mean the one which created child window using window.open...Demulcent
Marek: of course you can, using window.opener.methodName from the child.Unmentionable
Marek: of course you can, using window.opener.methodName from the child.Unmentionable
@Demulcent - It is possible but it's bad software design, doing so you are tightly coupling the two windows. A better way is to fire a specific EVENT in the parent passing any data along with that event object and then let the parent respond to that EVENT. You can fire EVENTs or Messages using the postMessage API and use a polyfill for earlier browsers however you will need a ref' to the window where you want to send the Event in the same way you need a ref' to the window if you invoke a function directly. This though doesn't help the original question so LocalStorage is a better mechanism.Affenpinscher
@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.Acrilan
@Acrilan I'm slightly embarrassed that I wrote that. I must have been angry that day or something. My apologies.Sattler
Please not the you cannot access properties of the pop up if they are in different originClovis
I
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);
        }
    });
Intrigue answered 9/6, 2015 at 14:38 Comment(3)
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.Nessa
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-eventsOlia
You don't need to wait for DOM readiness in order to access localStorageCarlina
N
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.

Number answered 11/12, 2016 at 20:2 Comment(2)
It's no longer experimental, even tho Edge might have not implemented it (it's marked ? in MDN)Kayne
Edge has it now.Athal
I
12

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", "*");
Ilsa answered 11/5, 2016 at 6:13 Comment(2)
Does it works on all browsers?Sanitarian
@StepanYakovenko support for browsers: developer.mozilla.org/en-US/docs/Web/API/Window/…Ilsa
H
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.

Hollo answered 1/8, 2013 at 21:35 Comment(1)
postMessage API is not designed for that https://mcmap.net/q/101604/-sending-a-message-to-all-open-windows-tabs-using-javascript You need the reference of targeted window to post a message for that specific windowHotblooded
P
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

Pentose answered 10/8, 2014 at 3:8 Comment(2)
One problem here is, that we can not (without being hacky) share a link to our synced view...Ohare
@Ohare 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: #9994620 . 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.Pentose
T
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.

Trochanter answered 13/6, 2014 at 22:0 Comment(2)
Can you add a link to this library?Eddington
@DennisNerush github.com/jcubic/sysend.jsTrochanter
J
-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).

Jenine answered 11/4, 2012 at 17:40 Comment(5)
Question was not about Flash.Amiss
This won't work in most mobile situations.Autoerotic
To be fair, Flash runs "a form of" Javascript just as the OP requestedTushy
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?Aubergine
OK, he has left the building. Can somebody else chime it?Aubergine

© 2022 - 2024 — McMap. All rights reserved.