Exploring the Broadcast Channel API
Tags: react, webdev, javascript
Published: 2020-02-20 19:59:05

---
title: Exploring the Broadcast Channel API
published: true
description: A quick look at using the Broadcast Channel Web API in React
tags: react, webdev, javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/frnmi02qrjvlgeiaqei4.jpg
---

You know those digital menu boards that you see at quick service restaurants? Well, last year I got to work on one of those.

> Ok, but what does that have to do with the Broadcast Channel API?

## A little bit of background

In our particular case, the menu board is a React web app running in a Chromebox at the restaurant. It supports two displays and we control which page of the menu it shows based on the URL route.

![Two Browser windows showing different menu pages](https://dev-to-uploads.s3.amazonaws.com/i/5kqsbigjs5wu3h5lvlit.png)

One of the requirements was that we needed to animate certain elements in the menu, but there was a catch. The animations _had_ to be synchronized across the displays. We couldn't just fire up the animation loop whenever we wanted. We needed a way for the two pages to communicate with each other to start their timers at the same time. 

Enter the [Broadcast Channel API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API).

## What is the Broadcast Channel API?

It is a Web API that allows basic communication between browsing contexts (i.e. windows, tabs, iframes, webviews) on the same origin.

![Two browser windows communicating through a broadcast channel](https://dev-to-uploads.s3.amazonaws.com/i/w1c7a961fq57lxoflzk4.png)

You start by creating a `BroadcastChannel` object and giving it a name. If a channel with the same name already exists, it will join the channel instead.

```javascript
const channel = new BroadcastChannel("channel_name")
```

To send a message you call the `postMessage()` method on the created object, which takes any object as an argument.

```javascript
channel.postMessage("is this thing on?")
```

This will dispatch a `message` event to each of the contexts that have joined the channel. We can then run a function for this event with the `onmessage` event handler. 

```javascript
channel.onmessage = ev => {
  console.log(ev.data)
}
// is this thing on?
```

To disconnect from the channel you call the `close()` method on the object.

```javascript
channel.close()
```

## Back to our app

We were able to leverage this API to communicate back and forth between the two displays and make sure they start their animation loop exactly at the same time. Keep in mind that each display "boots up" independently at slightly different times, so we need some negotiation up front to know when both of them are ready.

The basic logic looks something like this:

```javascript
/**
 * In this example I will refer to the first display to finish 
 * booting up as "display 1". The second one to be ready will
 * be "display 2".
 */

// display 1 creates the channel; display 2 joins it
const syncChannel = new BroadcastChannel("animation-sync")

syncChannel.onmessage = ({ data }) => {
  switch (data.type) {
    // display 1 receives the "READY" message from display 2
    // and posts a message to start setting things up
    case "READY": {
      syncChannel.postMessage({ type: "START" })
      break
    }
    // display 2 receives the "START" message
    case "START": {
      // record the current time (just to be safe we pad it 5s
      // to allow display 1 to receive the next message)
      const syncTime = new Date().getTime() + 5000
      
      // outside function that schedules the animations
      scheduleAnimations(syncTime)
      
      // send "SYNC" message to display 1 with the syncTime      
      syncChannel.postMessage({ type: "SYNC", syncTime })
      break
    }
    // display 1 receives the "SYNC" message with the syncTime
    case "SYNC": {
      scheduleAnimations(data.syncTime)
      break
    }
    default:
      break
  }
}

// display 2 sends the "READY" message to display 1
animationSyncChannel.postMessage({ type: "READY" })
```

## Play with it

I made [a simplified demo of this](https://codesandbox.io/s/react-broadcast-channel-api-84en5?fontsize=14&theme=dark) in Codesandbox. And here's a short preview of it:

![Animated gif of two browser windows showing a synchronized timer](https://dev-to-uploads.s3.amazonaws.com/i/drmkrizbr0x2nnamt4v1.gif)

Pretty cool, right?

## Caveat

Not every browser supports this natively. Fortunately, there's a npm package called [broadcast-channel](https://www.npmjs.com/package/broadcast-channel) that has the same API and uses the native implementation in browsers that support it. Plus, it allows you to use it in Node too!

***
Cover photo by [Prince Abid](https://unsplash.com/photos/LeZItQhwFks)