CloudSignal Docs
Use Cases

Real-Time Sync

Sync cursors, edits, and shared state across multiple clients using CloudSignal's pub/sub messaging.

Real-time sync keeps shared state consistent across multiple clients. When one user moves a cursor, edits a field, or updates a value, every other participant sees the change instantly. CloudSignal's pub/sub model makes this straightforward - clients publish changes to shared topics, and all subscribers receive updates in real time.

Architecture

Multiple clients subscribe to the same room topics. When any client publishes a change, the broker fans it out to all other subscribers immediately.

Real-Time Sync
Client A
publish
sync/doc-123
Client B
Client C
Client D

Each client both publishes and subscribes, creating a bidirectional sync loop. The broker handles fan-out - no server-side relay is needed.

Topic Design

Organize sync topics by room and field to keep updates granular:

sync/{room_id}/{field}

Examples:

TopicPurpose
sync/doc-123/contentDocument body changes
sync/doc-123/cursorsLive cursor positions
sync/doc-123/selectionsText selection highlights
sync/whiteboard-9/objectsWhiteboard object state

Splitting by field prevents unnecessary re-renders. A cursor movement does not trigger a content update handler, and vice versa.

How It Works

  1. Client connects to CloudSignal and subscribes to all topics for its room (sync/doc-123/#)
  2. User makes a change - the client publishes the delta to the relevant topic
  3. Broker fans out the message to all other subscribers on that topic
  4. Each client applies the incoming delta to its local state

Messages are typically published at QoS 0 for lowest latency. For collaborative editing where every keystroke matters, QoS 0 is acceptable because the next update will correct any missed frame.

For document editing, send operational transforms or CRDTs as the message payload rather than the full document. This minimizes bandwidth and avoids overwrite conflicts.

Implementation with @cloudsignal/collaborate

The @cloudsignal/collaborate SDK provides React components that handle connection management, cursor rendering, and state synchronization out of the box.

Wrap Your App with Space

import { CloudSignalProvider, Space } from '@cloudsignal/collaborate'

function App() {
  return (
    <CloudSignalProvider
      host="wss://connect.cloudsignal.app:18885/"
      token="your-token"
    >
      <Space id="doc-123">
        <CollaborativeEditor />
      </Space>
    </CloudSignalProvider>
  )
}

Add Live Cursors

import { CursorOverlay, useSelf } from '@cloudsignal/collaborate'

function CollaborativeEditor() {
  const self = useSelf()

  return (
    <div style={{ position: 'relative' }}>
      <CursorOverlay />
      <textarea
        onPointerMove={(e) => {
          self.updatePresence({
            cursor: { x: e.clientX, y: e.clientY }
          })
        }}
      />
    </div>
  )
}

Sync Shared State

import { useSharedState } from '@cloudsignal/collaborate'

function Counter() {
  const [count, setCount] = useSharedState('counter', 0)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  )
}

Every call to setCount publishes the new value to the sync topic. All other clients in the same Space receive the update and re-render.

Raw MQTT Example

If you are not using React or prefer direct MQTT control:

import { connect } from '@cloudsignal/mqtt-client'

const client = await connect({
  host: 'wss://connect.cloudsignal.app:18885/',
  username: 'sync-user',
  password: 'your-token'
})

// Subscribe to all fields in the room
await client.subscribe('sync/doc-123/#')

// Listen for updates from other clients
client.on('message', (topic, payload) => {
  const field = topic.split('/').pop()
  const data = JSON.parse(payload.toString())
  applyUpdate(field, data)
})

// Publish a change
client.publish('sync/doc-123/content', JSON.stringify({
  user: 'alice',
  delta: { position: 42, insert: 'hello' }
}))

Next Steps

On this page