---
title: Custom Displays & SDK
summary: Build your own room or lobby UI, connect it with the Meeting Room 365 SDK, and deploy to a managed kiosk — config sync, calendar actions, and fleet control from Admin.
lastReviewed: 2026-06-10
products:
  - room-displays
  - status-boards
  - platform
status: published
---

# Custom Displays & SDK

Meeting Room 365 is not only built-in door themes and status-board layouts. You can **host your own web app** — your HTML, your framework, your brand — and run it on the same **managed kiosk fleet** as standard room displays: display keys, Admin configuration, online/offline status, remote restart, MDM provisioning, and (when you connect a calendar) the same booking actions employees expect.

**The story in three steps:**

1. **Build** a web app (static page, React, Vue, or anything that runs in a browser).
2. **Drop in the SDK** when you want Admin-driven config, heartbeat, and remote commands — or start with **just a URL** and add the SDK later.
3. **Deploy** by creating a **Custom** display in Admin and opening your URL on a [native kiosk app](../room-displays/hardware-and-devices.md) or fullscreen browser.

Examples and the open **Platform SDK** live at **[sdk.meetingroom365.com](https://sdk.meetingroom365.com)**. Full **calendar-connected** and **multi-room board** SDK bundles are available through Meeting Room 365 — [contact support](mailto:support@meetingroom365.com) for access, licensing, and solution design.

## When to use a custom display

| Use a **built-in theme** (v3, SDK preview themes, status-board themes) | Use a **custom display** + SDK |
|------------------------------------------------------------------------|--------------------------------|
| Standard meeting room or lobby board with Admin theme editor | Bespoke UX, proprietary workflows, or deep integration with your intranet |
| Fast rollout, minimal engineering | You have front-end developers and a hosted URL |
| Calendar + booking toggles only | Dibs-style apps, hybrid sensors, split-screen compositions, or non-calendar signage that still reports **occupied** to Admin |

Custom displays use the **same room display licence** and kiosk deployment model as standard meeting room tablets unless support quotes a specific SDK or signage arrangement.

## Minimum viable setup — URL only

You do **not** need JavaScript to get started.

1. Host any HTTPS page (your design, your logic).
2. In Admin → **New Display** → **Custom**, enter the **redirect URL** (your app).
3. Copy the **display key** and open the app on a kiosk with `?key=yourDisplayKey` in the query string (the native app can inject the key via [MDM AppConfig](../room-displays/hardware-and-devices.md#kiosk-lockdown-and-mdm) so users never type it).

Without the SDK, Meeting Room 365 still routes the tablet to your URL and tracks the display in Admin at a basic level. Add the **Platform SDK** when you want live **configuration sync**, **online status**, **hardware telemetry**, and **remote commands** from Admin.

## Platform SDK (open — npm & sdk.meetingroom365.com)

The **Platform SDK** is the foundation for every custom display. It is published as **[meetingroom365](https://www.npmjs.com/package/meetingroom365)** on npm and documented at **[sdk.meetingroom365.com](https://sdk.meetingroom365.com)** (source mirrors `meetingroom365-sdk` on GitHub).

### Install

**Script tag (CDN):**

```html
<script src="https://cdn.jsdelivr.net/npm/meetingroom365@latest"></script>
```

**npm:**

```shell
npm install meetingroom365
```

Optional: **[ua-parser-js](https://www.npmjs.com/package/ua-parser-js)** so Admin receives structured device/OS fields from kiosks.

### Initialize

The display key comes from the **`?key=`** query parameter on the kiosk (or pass `key` explicitly in code for development).

```html
<script src="https://cdn.jsdelivr.net/npm/meetingroom365@latest"></script>
<script type="module">
  const displayConfig = await Meetingroom365.init({
    onUpdate(displayConfig) {
      // Admin saved changes — refresh branding, toggles, or layout
    },
  });
  console.log('Config from Admin', displayConfig);
</script>
```

**Callback style** (broader browser compatibility):

```html
<script>
  Meetingroom365.init({}, function (displayConfig) {
    console.log('Config from Admin', displayConfig);
  });
</script>
```

### What the Platform SDK gives you

| Capability | Purpose |
|------------|---------|
| **`init()` / `getDisplayConfigByKey()`** | Load the display configuration object managed in Admin (name, branding fields, feature toggles, custom JSON) |
| **`onUpdate` / remote `update` command** | Re-fetch config when an admin saves changes — no manual refresh |
| **`updateStatus({ … })`** | Push arbitrary status to Admin (e.g. `{ occupied: true }` for a Dibs-style room, custom sensor state, or app-specific health) |
| **Heartbeat & device info** | Periodic online signal plus screen size, user agent, optional battery — visible under **Devices** in Admin |
| **WebSocket + polling command channel** | Receive **restart**, **update**, **screenshot**, and other fleet commands initiated from Admin |
| **`addAction` / `on`** | Register handlers for remote commands |
| **Native app bridge** | When running inside the Meeting Room 365 **native kiosk app**, `postMessage` exchanges device info with the Capacitor shell |

### Configuration options (library-level)

Pass these to `init({ … })` — they control SDK behavior, not the Admin display editor:

| Option | Default | Meaning |
|--------|---------|---------|
| `key` | from `?key=` | Display key override |
| `onUpdate` | — | Called when Admin pushes a config refresh |
| `STATUS_UPDATE_INTERVAL` | 15 minutes | How often to POST online / hardware status |
| `UPDATEDEVICESTATUS` | false | Also write status-state used by some Admin views |
| `LOCATION` | true | Include IP-based rough location in status (same privacy model as standard displays — see [Administration — Data and privacy](../administration/index.md#data-and-privacy)) |

### Example: Dibs-style occupancy

The **[Good Place example](https://sdk.meetingroom365.com/examples/goodplace)** on sdk.meetingroom365.com shows a minimal custom UI that calls `Meetingroom365.updateStatus({ occupied: true })` when someone reserves and `{ occupied: false }` when they release — no calendar connection required.

## Deploy to a managed kiosk

Custom displays use the **same fleet path** as standard room tablets:

1. **Admin** → **New Display** → **Custom** → name + **redirect URL** → create.
2. Copy the **display key** from the display editor.
3. **Native kiosk app** (recommended): install Meeting Room 365 on iPad/Android, enter the key — the app loads your URL full-screen. See [Hardware & devices](../room-displays/hardware-and-devices.md).
4. **MDM**: push the display key via AppConfig; optionally push a start URL that includes `?key=`.
5. **Browser / digital signage**: open `https://your-app.example/?key=displayKey` on a locked-down browser or signage player.

Your app should assume **portrait or landscape** kiosk resolutions, **offline** periods, and **long-running** sessions (the Platform SDK reconnects command channels automatically).

Admin **bulk utilities** (restart, screenshot, cache clear, lock) apply to custom displays the same as built-in room displays when the SDK is loaded and the device is online.

## Room Display SDK — calendar-connected single room

**Distribution:** contact [support@meetingroom365.com](mailto:support@meetingroom365.com). This is the JavaScript layer used by Meeting Room 365 **SDK preview themes** (Signal, Cumulus, Meridian, Reykjavik, Magnolia, Atrium) and custom calendar-connected builds. It sits **on top of** the Platform SDK.

**Purpose:** One **room mailbox** — live meetings, derived free/busy, and **walk-up booking actions** with the same permission rules as built-in v3 themes, exposed as a reactive state object for your UI framework.

### Architecture

```
Your UI (React, Vue, vanilla, …)
        ↕ subscribe / actions
Room Display SDK  (MR365.createDisplay)
        ↕ config + meetings + lock state
Platform SDK      (Meetingroom365.init)  →  Admin + fleet commands
        ↕
Meeting Room 365 calendar APIs (room mailbox configured in Admin)
```

Load order: **Platform SDK first**, then the Room Display SDK bundle, then `MR365.createDisplay()`.

### State model (conceptual)

After `ready()`, subscribe to a single state object that includes:

| Field | Meaning |
|-------|---------|
| `config` | Sanitized display configuration from Admin (toggles, branding, locale, booking flags) |
| `events` | Normalized upcoming meetings for the room |
| `current` / `next` | Derived active and next meetings |
| `status` | `'free'`, `'busy'`, `'starting-soon'`, etc. |
| `minutesLeft` / `minutesUntilStart` | Countdown helpers |
| `can` | `{ book, extend, endEarly, checkIn, reserve, roomFinder }` — what walk-up actions are allowed **right now** |
| `locked` | Display lock / secret required for API access |
| `online` / `ready` / `lastSync` | Connectivity and first successful fetch |
| `error` | Structured failure (`not-found`, `unauthorized`, `network`) for theming error screens |
| `location` / `weather` | Optional IP-based location and Open-Meteo weather when enabled in config |

Private meetings are redacted in normalized events (`title: 'Private'`, empty organizer).

### Actions (calendar interaction)

The SDK exposes debounced action methods that honor Admin toggles and calendar provider rules:

| Action | Typical use |
|--------|-------------|
| `book(minutes)` | Instant reserve for N minutes |
| `extend(minutes)` | Extend current meeting |
| `endEarly()` | End current meeting early |
| `checkIn(meetingId)` | Force check-in when enabled |
| `reportIssue(payload)` | Notify administrator from the tablet |
| `roomFinder.list()` / `roomFinder.subscribe()` | Nearby free rooms for the tenant |
| `reservationUrl()` | Future custom-reservation wizard URL when enabled |

Failed actions return `{ ok: false, reason: … }` rather than throwing — UI should surface messages inline.

### Other surfaces

| Surface | Use |
|---------|-----|
| `subscribe(fn)` / `on('status', fn)` | React/Vue/Svelte external-store pattern |
| `format.time` / `format.date` / `format.clock` | Locale-aware formatting driven by Admin `locale`, `twentyfour`, `intdates`, `sinodates` |
| `t(key, vars, fallback)` | Admin `i18n` dictionary lookups |
| `weatherLabel(weather)` | Localized weather strings when `config.weather` is on |
| `commands.send(cmd, value)` | Escape hatch to fleet command channel |
| Demo / preview modes | `?demo=1` loads fixture meetings without a calendar; `?preview=1` overlays real branding from Admin onto fixture data for sales screenshots |

### Calendar connection

Custom calendar-connected displays still connect a **room mailbox in Admin** (Microsoft 365, Google Workspace, or Exchange) the same way as a standard meeting room display. The SDK reads meetings through Meeting Room 365 — **calendar content is not stored** on Meeting Room 365 servers (same posture as [built-in room displays](../room-displays/calendar-connections.md)).

For optional **calendar-on-device** deployments (service user on the tablet), discuss architecture with support — most SDK themes use the standard Admin connection path.

## Status Board SDK — multi-room read-only

**Distribution:** contact [support@meetingroom365.com](mailto:support@meetingroom365.com). Companion to the Room Display SDK for **lobby boards** you build yourself.

**Purpose:** Aggregate **many rooms** into one board UI — occupied/free, timelines, sorting — without duplicating status-board server logic. **Read-only:** no booking from the board (same rule as [built-in status boards](../status-boards/index.md)).

### Architecture

```
Your board UI
        ↕ subscribe
Status Board SDK  (MR365.createBoard)
        ↕ per-room meeting fetches + derivation
Platform SDK (optional)  →  Admin heartbeat / restart
```

### State model (conceptual)

| Field | Meaning |
|-------|---------|
| `config` / `settings` | Board display configuration from Admin (theme, group, sort, privacy flags) |
| `rooms[]` | Each room: `localKey`, `name`, `occupied`, `capacity`, `locationString`, full-day `events[]`, etc. |
| `ready` / `online` / `lastSync` / `error` | Load and connectivity |

Room list resolution follows the same concepts as Admin **Group name**, **Offline Displays**, and domain scoping on built-in status boards.

### API surface

| Method | Meaning |
|--------|---------|
| `subscribe(fn)` / `on('change', fn)` | Re-render when any room status changes |
| `ready()` | Promise when first aggregation pass completes |
| `refresh()` | Force a sync |
| `destroy()` | Tear down timers |
| `format.time` / `format.date` / `format.clock` | Shared formatting helpers |

Polling is **adaptive** — faster during business hours, relaxed overnight.

## SDK preview themes (reference implementations)

Meeting Room 365 ships **designer-built preview themes** (Signal, Cumulus, Meridian, Reykjavik, Magnolia, Atrium) that demonstrate what the Room Display SDK can render. They appear in Admin’s theme picker as SDK options and can be used as **starting points** for custom forks.

For production custom work, teams typically:

- Fork a preview theme’s interaction patterns, or
- Build greenfield UI against `MR365.createDisplay()`, or
- Engage Meeting Room 365 support for solution architecture and SDK access

See [Themes & customization — SDK themes](../room-displays/themes-and-customization.md) for how preview themes relate to v2/v3 built-in layouts.

## Split-screen and composite URLs

Admin’s Custom display flow includes examples that combine **multiple display keys** in one layout (grid splits showing several rooms on one screen). These are hosted Meeting Room 365 composition pages — useful patterns when prototyping; contact support for production composite signage.

## Supported / not supported

| Supported | Not supported (without custom engineering) |
|-----------|---------------------------------------------|
| Custom HTTPS web app on native kiosk or browser | Native Swift/Kotlin UI outside a WebView — use the kiosk app wrapping your web app |
| Platform SDK via npm / CDN | Publishing Room Display or Board SDK bundles yourself — obtain through Meeting Room 365 |
| Dibs / manual occupancy via `updateStatus` | Visitor check-in flows on a custom URL — use [Visitor management](../visitor-management/index.md) display keys |
| Calendar-connected custom UI with Room Display SDK | Meeting Room TV join inside a custom page — use [Meeting Room TV](../meeting-room-tv/index.md) |
| Multi-room read-only board with Board SDK | Writable status board (booking from lobby) — booking stays on door displays |
| Remote restart, screenshot, config push from Admin | Arbitrary native API access to the tablet OS outside the Meeting Room 365 app shell |

## Best fit for

- **Workplace product teams** that need a branded room experience beyond theme CSS
- **Integrators** building vertical solutions (healthcare, education, events) on room calendars
- **Signage partners** deploying Meeting Room 365 kiosks with partner-hosted creative
- **Developers** prototyping Dibs, sensors, or hybrid occupancy before committing to a calendar connection

## Frequently asked questions

**Do we need the SDK if we only have a static page?**  
No. Custom display type only requires a **URL**. Add the Platform SDK when you want Admin config sync and fleet visibility.

**Where is the display key passed?**  
Query parameter **`?key=`** on your URL, MDM AppConfig, or explicit `init({ key: '…' })` during development.

**Is the Platform SDK free?**  
Yes — npm package and sdk.meetingroom365.com examples are public. Room Display and Board SDK bundles are **gated** — email [support@meetingroom365.com](mailto:support@meetingroom365.com) for access, licensing, and partner terms.

**Can we use React or Vue?**  
Yes. Any framework that builds to static assets on HTTPS works. Use `subscribe()` or `ready()` from the Room Display SDK as an external store.

**How is this different from custom CSS on v3?**  
[v3 custom CSS](../room-displays/themes-and-customization.md) restyles the **built-in** renderer. Custom displays **replace** the renderer entirely with your hosted app.

**Does SSO apply to custom displays?**  
Staff **Admin** access uses the same [delegated SSO](../administration/index.md#sign-in-and-identity). Walk-up users on the tablet interact with **your** UI; calendar actions go through the room mailbox configured in Admin.

**Can LLMs help us build against the SDK?**  
Yes. Point assistants at this guide, [sdk.meetingroom365.com](https://sdk.meetingroom365.com), and the npm README. For calendar-connected and board SDKs, request the bundle from support — documentation for integrators ships with the bundle.

## Get started

1. Browse **[sdk.meetingroom365.com](https://sdk.meetingroom365.com)** and the [Good Place example](https://sdk.meetingroom365.com/examples/goodplace).
2. Create a **Custom** display in [Admin](https://admin.meetingroom365.com).
3. Deploy to a [kiosk tablet](../room-displays/hardware-and-devices.md).
4. Email **[support@meetingroom365.com](mailto:support@meetingroom365.com)** when you need Room Display SDK, Board SDK, or solution review.

## Related

- [Administration — Creating displays](../administration/index.md#creating-and-claiming-displays)
- [Room displays — Themes & customization](../room-displays/themes-and-customization.md)
- [Status boards](../status-boards/index.md)
- [Hardware & devices — MDM](../room-displays/hardware-and-devices.md#kiosk-lockdown-and-mdm)
- [Getting started](../getting-started.md)
