Skip to main content

Intro


This tutorial builds two Custom Apps that talk to each other in real time using App Broadcasting. You’ll create:
  1. Selector App — a data table that publishes a selection:changed message whenever a user clicks a row
  2. Detail App — a panel that subscribes to selection:changed and shows details for the selected record
Along the way you’ll learn how to:
  • Declare broadcast channels in manifest.json
  • Publish and subscribe with domo.broadcast() and domo.onBroadcast()
  • Sync current state when an app mounts late (the bus keeps no history)
  • Filter messages by source with domo.onBroadcastFrom()
Prerequisites: Complete the Setup and Installation guide. You’ll place both apps on the same Domo page, and the app-broadcasting feature switch must be enabled on your instance.

Step 1: Scaffold both apps


Create two separate app projects:
Each produces a Vite + React + TypeScript project ready for Domo development.

Step 2: Configure the Selector App manifest


Open selector-app/manifest.json and add the channels and datasetsMapping properties:
The channel name selection:changed uses the namespace:event convention: the namespace groups related channels; the event describes what happened.

Step 3: Build the Selector App component


Replace selector-app/src/App.tsx:

Step 4: Configure the Detail App manifest


Open detail-app/manifest.json:
The Detail App has no datasets of its own — it gets all its data from the Selector App’s messages.
Note: In production, an app receives a channel only if that channel is listed under subscribes. Declaring selection:changed here is what wires the Detail App up to receive it.

Step 5: Build the Detail App component


Replace detail-app/src/App.tsx:
onBroadcast returns an unsubscribe function — call it in the effect cleanup so the subscription is removed when the component unmounts.

Step 6: Publish and test


Publish both apps and place them on the same App Studio page:
In Domo, create a new App Studio page and add both apps as cards. Broadcasting happens automatically once both apps are on the same page — you don’t configure any routing. Click a row in the Selector App, and the Detail App updates instantly.

Pattern: Sync current state on mount


The bus keeps no history, so if the Detail App mounts after a row was already selected, it starts empty until the next click. To catch up, have the Detail App request the current selection when it mounts, and have the Selector App answer by republishing. Add a request channel to both manifests — subscribes in the Selector, publishes in the Detail:
In the Selector App, answer requests by republishing the last selection:
In the Detail App, ask for the current selection right after subscribing:

Pattern: Filtering by source


If a page has multiple Selector Apps and you only want to listen to one, use domo.onBroadcastFrom():
The instance ID is the sourceAppId on any message that app sends — it identifies a specific card instance on the page, so two copies of the same app have different IDs. Like onBroadcast, this returns an unsubscribe function.
Note: A visual broadcasting inspector for viewing live channel traffic and instance IDs is on the roadmap. Until then, log sourceAppId during development to find an instance’s ID.

Pattern: Multi-channel coordination


Real apps often use several channels. Here’s a Selector App that publishes both selection and hover events:
The subscriber decides which channels it cares about:

Pattern: One-time initialization


Use domo.onBroadcastOnce() when an app only needs a message once — for example, an initial configuration from a coordinator app. It unsubscribes automatically after the first delivery:

Error handling


domo.broadcast() returns immediately and never throws. If the host rejects a message — a reserved domo: channel, a payload over 64 KB, more than 100 messages per second, or the feature switch being off — it notifies only the sending app, and the SDK writes a warning to the browser console:
Because there’s no thrown error to catch, watch the console during development, and design publishers to stay within the limits (for example, throttle high-frequency events like hover before broadcasting).

Summary


Next steps