MQTT integrations

Build an external service that follows Presenter or exchanges messages on your own topics. Persistent credentials have a one-time password and narrowly chosen permissions. They never grant presentation commands.

Local credentials require a paid Presenter Own, Flex or eligible legacy licence, including Presenter through Complete. They stay on that computer and do not require a cloud account. SundayAssist Cloud requires an active Complete subscription, sign-in, organisation membership and an owner or administrator role. An unpaid pilot does not qualify.

Create credentials

  1. Open Connections → Phone remote → Integration credentials and choose Local or SundayAssist Cloud.
  2. Choose Create credentials, give the service a recognisable name, and enter its Publish topics and Subscribe topics, one per line. Leave an unused direction empty. For the example below, enable Read Presenter events and leave custom topics empty.
  3. Save the password immediately in the service’s secret store. Copy connection details includes it. The password is shown once and cannot be recovered later.
  4. Use a separate credential for each service. A credential permits up to 20 topic entries. Up to 20 may be active per local installation, or per account and organisation in the cloud.

Connect to the right broker

Use MQTT 3.1.1 or 5. Copy the actual local address and bound ports shown by Presenter; the usual TCP port is 1883 and WebSocket port 9883, with fallback ports when busy. The local connection is unencrypted: keep it on a trusted network and never forward these ports to the internet. Cloud TLS uses port 8883; secure WebSocket uses port 443 and path /mqtt. Keep certificate verification enabled. Every simultaneous connection needs a unique client ID beginning with the assigned prefix.

Local:
  mqtt://<presenter-lan-ip>:1883
  ws://<presenter-lan-ip>:9883/mqtt
Complete cloud:
  mqtts://mqtt.sundayassist.com:8883
  wss://mqtt.sundayassist.com/mqtt
username: <generated-username>
password: <shown-once-password>
clientId: <assigned-client-id-prefix>external-1

Choose custom topics

Publish permissions name exact topics. Subscribe permissions allow an exact topic or a final /# below a literal namespace, such as church/lyrics/#. The + wildcard, a bare #, empty levels, whitespace and $ are rejected. Your first namespace cannot be sundayassist, regardless of letter case. The explicit read-only events permission is the reserved exception.

Local permissions apply to that Presenter installation. Cloud topics are isolated within the organisation: use the same topic on both clients, without adding an organisation prefix. People in the same organisation with overlapping topic grants can exchange messages. Integration credentials cannot pair Remote, access its deck/state protocol, use AI, relay or Presenter-link, or publish to SundayAssist-owned topics. Custom publishing permits QoS 0 or 1, no retained flag and payloads up to 1 MiB.

Read Presenter events

Enable Read Presenter events and subscribe to sundayassist/integrations/v1/events/#, or narrow it to sundayassist/integrations/v1/events/<presenterId>/state. Presenter publishes a retained QoS 1 JSON snapshot with the following public contract. Titles are included; lyrics, notes, file paths, screenshots and account details are excluded. The cue or section may be null.

{
  "schemaVersion": 1,
  "eventId": "boot-id:42",
  "presenterId": "opaque-installation-id",
  "runId": "boot-id",
  "sequence": 42,
  "occurredAt": "2026-10-27T12:00:00Z",
  "type": "presenter.state",
  "state": {
    "presenting": true,
    "blanked": false,
    "phase": "active",
    "cue": {"id": "opaque-occurrence", "type": "lyrics", "title": "Welcome", "index": 0},
    "section": {"id": "opaque-section", "title": "Gathering", "index": 0},
    "position": {"subIndex": 0, "page": 0}
  }
}

Treat eventId as the deduplication key and order messages by sequence within the same runId. A Presenter restart creates a new run. Reconnecting may replay the same event. Cue and section IDs identify opaque occurrences; editing or reordering the deck can change them. Indices are zero-based; subIndex can be -1 for a default slide.

Changes are coalesced for up to 1 second, with a fresh snapshot normally every 15 seconds even if nothing changes. Read occurredAt and the MQTT retained indicator before acting. A retained snapshot can outlive a running Presenter and is not proof that it is online. This is the latest known state, not a complete event log or upcoming rundown.

Try the Node.js live desk

Download the working example or open the simulated preview. With Node.js 22 or later, the following runs a live cue view and an observed-cue timeline without a broker or licence:

unzip mqtt-showcase.zip
cd mqtt-showcase
npm ci
npm run demo

For real events, copy .env.example to .env and fill the generated broker URL, username, password and client-ID prefix. Set PRESENTER_ID when several Presenters share the cloud organisation, then run npm start. Open http://127.0.0.1:4188. The first Presenter is selected when no ID is given. Credentials remain in Node; the browser receives only projected event fields over Server-Sent Events. Keep .env private. The sample is a local development server, not a shared hosted service.

For Node-RED, connect an MQTT in node to the copied broker address. Enter the generated username, password and a unique client ID with the assigned prefix; enable certificate-verified TLS for cloud. Set the event topic above and QoS 1, then connect JSON → debug. Read msg.payload.state.cue.title, check msg.payload.occurredAt, and deduplicate msg.payload.eventId before triggering an action. See the official MQTT.js reference and Node-RED MQTT cookbook.

Receive live text

For local live text, give the external service publish access to church/lyrics/slide. In Connections → Phone remote → Same Wi-Fi, set Lyrics topic to church/lyrics/slide. Add Live streaming lyrics from the library to your deck and present that cue. Publish plain UTF-8 text, not a JSON wrapper, from the service to the local broker.

For Complete cloud live text, create a separate credential in the same organisation with only subscribe access to church/lyrics/slide. Choose Own server in Presenter, enter wss://mqtt.sundayassist.com/mqtt plus those credentials and the same Lyrics topic, then save and test. The local phone connection remains available. Selecting Own server uses this manual connection instead of automatic Anywhere (Complete); integration credentials do not provide cloud Remote access.

Replace, revoke and handle interruptions

Replace password invalidates the old connection details and shows new ones once; update every client using that credential. Revoke permanently disables it. Local credentials persist across Presenter restarts; passwords have no scheduled expiry. Paid access and permissions remain enforced. You can still list and revoke credentials after paid access ends.

Cloud eligibility and active connections are checked about every 30 seconds. Revocation is not instantaneous; a policy-service interruption can delay disconnection by a few minutes. Cloud clients must reconnect at least hourly using the same current password. Enable automatic reconnect and resubscription. QoS 1 can duplicate messages; network loss, maintenance and failover can interrupt delivery. Make side effects safe to repeat and keep prepared local content available. TLS protects the network connection, not end-to-end message content.