Mirror JavaScript API for templates

Mirror renders the screen by loading an HTML5 template from its flash memory, and populating it with data (context!) incoming from mobile devices, or by scanning the environment in search of Bluetooth beacons.

You can learn more about templates in Build your own template or Templates with beacon triggers.

This page documents the JavaScript API you can use in your template to adapt it to the context of the environment.

What’s ahead (aka Table of Contents)


All the interactions with the API are through a global mirror object.

You must initialize it with mirror.init() first!

React users might have to explictly import mirror and Mirror objects from window into their scope:

const { mirror, Mirror } = window;

Receiving user data

This is usually the data sent from the mobile devices (“clients”). For example, an airport app sending the user’s flight info to show on the screen.

mirror.listen(Mirror.Events.USER_DATA, {
    ondata: function(event) {
        // this is the data received
        // use it to manipulate the DOM and show it on screen

        // this is a string identifier of the device that sent the data

Two more scenarios for ondata being called are:

  • If template X iniatiates a switch to template Y (see Switching to a different template below), ondata will also be called, with event.data being the data that template X chose to pass to template Y. If template X chose to pass no data, the ondata will still be called, but with empty event.data.

  • If a template is set as default, the Mirror OS itself initiating the switch to the default template immediately after boot, and this will also trigger ondata, with empty event.data.

Think about this as ondata always being called when the template is loaded, with event.data from a client that triggered the template, another template making a switch, or empty if it’s being loaded with no initial data.

Sending data back to clients

Templates can send some JSON data back to the client:

var clientId = event.from; // see `ondata` above

mirror.sendData(clientId, {
    field1: 11,
    field2: "Example"

On the client’s side, the data will be delivered to:

  • on iOS, the EMSDeviceConnectableDelegate and its didReceiveData method
  • on Android, the DisplayCallback and its onData method

See “Trigger the template from a mobile app” from “Build your own template” to see this delegate/callback in action.

Knowing when a client disconnects

This will come in handy to remove that client’s data from the screen.

mirror.listen(Mirror.Events.USER_DATA, {
    ondisconnect: function(event) {

Switching to a different template

Sometimes, when a client goes away, you might want to switch to a different template. For example, your default (“idle”) template is a list of upcoming flights, refreshed in real-time from your backend (e.g., via XHR polling). When a mobile app authorized to access your Mirror comes in range, it temporarily switches to a template that shows the user’s detailed flight info and a map to the gate. When the user goes away and the client disconnects, you can switch back to the default template.

// switch to the default template

// switch to a specific template

// you could also pass some data to the destination template
// it'll receive them in the `ondata` handler of the `USER_DATA` event
// (see "Receiving user data" above)
mirror.selectTemplate("flights", {last_flight_shown: "ABC123"});

Scanning for beacons with the Scanner API

Mirror’s Bluetooth is not just for receiving data from other devices. You can also use it to scan for Bluetooth beacons in range.

mirror.listen(Mirror.Events.SCAN, {
    onscan: function(event) {
        for (const device of event.devices) {

Every device has object has these properties:

mac: "d07b0935289a",
id: "51daa294adf782a6b7f82ada22acf105", // for Estimote Beacons, its identifier
                                        // otherwise, this is simply equal to `mac`
rssi: -84,
ts: 1498485899853, // timestamp in milliseconds for when the device has been
                   // last detected, and the data in the object updated/refreshed

For some known types of Bluetooth advertisements, there are extra properties included:

Estimote Nearable

Supported by Estimote Sticker beacons.

type: "nearable",

motion: false,           // is the beacon in motion
motionDuration: 3715200, // how long in its current motion state, in seconds
lastMotionDuration: 60,  //                 previous

x: -0.97, // accelerometer readings on the X axis, in "g" unit
y: -0.06, //                               Y
z:  0.01, //                               Z

temperature: 25.875,

battery: 2.95, // battery voltage

Estimote Telemetry

Supported by Estimote Proximity and Location beacons.

type: "telemetry",

motion: false,           // is the beacon in motion
motionDuration: 3715200, // how long in its current motion state, in seconds
lastMotionDuration: 60,  //                 previous

ax: -0.97, // accelerometer readings on the X axis, in "g" unit
ay: -0.06, //                               Y
az:  0.01, //                               Z

temperature: 25.875, // in degrees Celsius
pressure: 996.03,    // atmospheric pressure, in Pa

gpio0: true, // GPIO port 0 state, false/true = low/high
gpio1: true, // GPIO port 1 state, false/true = low/high

battery: 5.95,     // battery voltage
batteryLevel: 255, // battery level, 255 for "unknown"
uptime: 86313600,  // beacon's uptime in seconds


Supported by all Estimote Beacons, and many other beacons on the market.

type: "ibeacon",

uuid: "b9407f30f5f8466eaff925556b57fe6d",
major: 15746,
minor: 36399,

tx: -64, // known as "measured power" in the iBeacon spec
         // that is, what's the expected RSSI at 1 m away from the beacon


Supported by all Estimote Beacons, and many other beacons on the market.

type: "eddystone_url",
url: "https://twitter.com/estimote",


Supported by Estimote Proximity and Location beacons, and many other beacons on the market.

type: "eddystone_uid",
namespace: "edd1ebeac04e5defa017",
instance: "0bdb87539b67",

Scan filters

By default, Scanner API will deliver all beacons in range to your onscan handler. You can limit that with filters. Note that this is much more efficient than filtering the devices yourself in JavaScript, so make use of it!

    rssiRange: { low: -60, hi: -50 },
    ids: ["51daa294adf782a6b7f82ada22acf105", "4d5a7ea233981468"],
    types: ["telemetry", "nearable"]

Removing listeners

If you want to stop receiving data from mobile devices, or scan results from the Scanner API, simply remove the listener registered to the particular event:


Displaying debug messages on the screen

If you want to display a debug message on the screen you can use:

mirror.debugPopup('My debug message');

It will show a semi-transparent console at the bottom of the screen with your message in it. Each message will disappear after 20 s. When all the messages are gone, the console will disappear too.

You can also redirect the actual console messages to the debug popup:


// this will now show in the debug popup:
console.log("My debug message")

Tip: A friendly reminder to remove or comment-out your debugging code before going to production!

Important: This feature is experimental and available since firmware version 1.0.12. Make sure your Mirror is up to date.