CloudSignal Docs
Getting StartedUse Cases

Real-time applications

Build chat applications, live dashboards, collaborative tools, and multiplayer experiences with CloudSignal's real-time messaging.

CloudSignal powers real-time features in web and mobile applications, from chat and notifications to live dashboards and collaborative editing. This page walks through the most common patterns and the topic shapes that fit them.

Use cases

Chat applications

Build instant messaging with message history, typing indicators, and presence:

Two-user chat
User A
CloudSignal
User B
PUBLISH chat/room-123/messages
Deliver to subscribers
PUBLISH chat/room-123/typing
Show typing indicator

Implementation

// Chat room component using the CloudSignal SDK
function ChatRoom({ roomId, userId }: { roomId: string; userId: string }) {
  const [messages, setMessages] = useState<Message[]>([]);
  const [typingUsers, setTypingUsers] = useState<Set<string>>(new Set());
  const { client, isConnected } = useCloudSignal();

  useEffect(() => {
    if (!client || !isConnected) return;

    client.subscribe(`chat/${roomId}/messages`);
    client.subscribe(`chat/${roomId}/typing`);

    client.onMessage((topic, data: any) => {
      if (topic === `chat/${roomId}/messages`) {
        setMessages((prev) => [...prev, data]);
      } else if (topic === `chat/${roomId}/typing`) {
        setTypingUsers((prev) => {
          const next = new Set(prev);
          if (data.typing) next.add(data.userId);
          else next.delete(data.userId);
          return next;
        });
      }
    });
  }, [client, isConnected, roomId]);

  const sendMessage = (text: string) => {
    client?.transmit(`chat/${roomId}/messages`, {
      userId,
      text,
      timestamp: Date.now(),
    });
  };

  const setTyping = (isTyping: boolean) => {
    client?.transmit(`chat/${roomId}/typing`, {
      userId,
      typing: isTyping,
    });
  };

  // ... render UI
}

Live dashboards

Stream real-time data to dashboards:

// Dashboard receiving live metrics
function LiveDashboard() {
  const [metrics, setMetrics] = useState<Metrics | null>(null);
  const { client, isConnected } = useCloudSignal();

  useEffect(() => {
    if (!client || !isConnected) return;

    client.subscribe('metrics/realtime');

    client.onMessage((_topic, data: any) => {
      setMetrics(data);
    });
  }, [client, isConnected]);

  return (
    <div className="grid grid-cols-3 gap-4">
      <MetricCard title="Active users" value={metrics?.activeUsers} />
      <MetricCard title="Requests/sec" value={metrics?.requestsPerSec} />
      <MetricCard title="Latency" value={metrics?.avgLatency} unit="ms" />
    </div>
  );
}
# Backend publishing metrics
import threading
import time
import json

def metrics_publisher():
    while True:
        metrics = collect_metrics()
        client.publish(
            'metrics/realtime',
            json.dumps({
                'activeUsers': metrics['active_users'],
                'requestsPerSec': metrics['rps'],
                'avgLatency': metrics['latency_ms'],
                'timestamp': time.time(),
            }),
        )
        time.sleep(1)  # Update every second

threading.Thread(target=metrics_publisher, daemon=True).start()

Notifications

Push notifications to users in real time:

// Client: receive notifications
function NotificationListener({ userId }: { userId: string }) {
  const { client, isConnected } = useCloudSignal();

  useEffect(() => {
    if (!client || !isConnected) return;

    client.subscribe(`notifications/${userId}`);
    client.subscribe('notifications/broadcast');

    client.onMessage((_topic, notification: any) => {
      // Show browser notification
      if (Notification.permission === 'granted') {
        new Notification(notification.title, {
          body: notification.body,
          icon: notification.icon,
        });
      }
      // Or update in-app notification center
      addNotification(notification);
    });
  }, [client, isConnected, userId]);

  return null;
}
# Server: send notification
import json
import time

def send_notification(user_id: str, title: str, body: str):
    client.publish(
        f'notifications/{user_id}',
        json.dumps({
            'title': title,
            'body': body,
            'timestamp': time.time(),
        }),
        qos=1,  # Ensure delivery
    )

def broadcast_notification(title: str, body: str):
    client.publish(
        'notifications/broadcast',
        json.dumps({
            'title': title,
            'body': body,
            'timestamp': time.time(),
        }),
    )

Collaborative editing

Sync document changes in real time:

// Collaborative document editor
function CollaborativeEditor({ docId, userId }: { docId: string; userId: string }) {
  const [content, setContent] = useState('');
  const [cursors, setCursors] = useState<Map<string, CursorPosition>>(new Map());
  const { client, isConnected } = useCloudSignal();

  useEffect(() => {
    if (!client || !isConnected) return;

    client.subscribe(`docs/${docId}/changes`);
    client.subscribe(`docs/${docId}/cursors`);

    client.onMessage((topic, data: any) => {
      if (topic.endsWith('/changes') && data.userId !== userId) {
        applyRemoteChange(data.operation);
      } else if (topic.endsWith('/cursors') && data.userId !== userId) {
        setCursors((prev) => new Map(prev).set(data.userId, data.position));
      }
    });
  }, [client, isConnected, docId, userId]);

  const handleChange = (operation: Operation) => {
    setContent(applyOperation(content, operation));
    client?.transmit(`docs/${docId}/changes`, {
      userId,
      operation,
      timestamp: Date.now(),
    });
  };

  const handleCursorMove = (position: CursorPosition) => {
    client?.transmit(`docs/${docId}/cursors`, { userId, position });
  };

  // ... render editor with remote cursors
}

Multiplayer experiences

Sync state between players:

// Game-state sync
function MultiplayerGame({ gameId, playerId }: { gameId: string; playerId: string }) {
  const [players, setPlayers] = useState<Map<string, PlayerState>>(new Map());
  const { client, isConnected } = useCloudSignal();

  useEffect(() => {
    if (!client || !isConnected) return;

    client.subscribe(`games/${gameId}/state`);
    client.subscribe(`games/${gameId}/events`);

    client.onMessage((topic, data: any) => {
      if (topic.endsWith('/state')) {
        setPlayers((prev) => {
          const next = new Map(prev);
          next.set(data.playerId, data.state);
          return next;
        });
      } else if (topic.endsWith('/events')) {
        handleGameEvent(data);
      }
    });
  }, [client, isConnected, gameId]);

  // Send position updates at fixed interval
  useInterval(() => {
    const state = getPlayerState();
    client?.transmit(`games/${gameId}/state`, {
      playerId,
      state,
      timestamp: Date.now(),
    }, { qos: 0 }); // QoS 0 for high-frequency updates
  }, 50); // 20 updates per second

  // ... render game
}

Security for browser apps

Never expose permanent credentials in browser code. Mint short-lived tokens on your server.

import CloudSignal from '@cloudsignal/mqtt-client';

// 1. Request a token from your server (which holds the secret key)
const response = await fetch('/api/mqtt-token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ userId }),
});
const { accessToken } = await response.json();

// 2. Connect with the short-lived token
const client = new CloudSignal({
  preset: 'desktop',
  clientId: `browser-${userId}-${Date.now()}`,
});

await client.connectWithToken({
  organizationId: process.env.NEXT_PUBLIC_CLOUDSIGNAL_ORG_ID!,
  externalToken: accessToken,
});

See Server-side tokens for the full implementation.

Best practices

Topic design

# User-specific topics
notifications/{user_id}
chat/dm/{user_id_a}/{user_id_b}

# Room-based topics
chat/rooms/{room_id}/messages
chat/rooms/{room_id}/typing
chat/rooms/{room_id}/presence

# Broadcast topics
notifications/broadcast
system/status

Message size

Keep messages small for optimal performance:

// Good: minimal payload
client.transmit('game/state', {
  id: playerId,
  x: position.x,
  y: position.y,
  t: Date.now(),
});

// Avoid: oversized payload
client.transmit('game/state', {
  playerId,
  position: { x: position.x, y: position.y, z: 0 },
  velocity: { x: vel.x, y: vel.y, z: 0 },
  rotation: { x: 0, y: 0, z: rotation },
  health: 100,
  inventory: [...items],
  timestamp: new Date().toISOString(),
});

Throttle high-frequency updates

// Throttle cursor position updates
const throttledCursorUpdate = useMemo(
  () => throttle((position) => {
    client?.transmit(`docs/${docId}/cursors`, { userId, position });
  }, 50), // Max 20 updates per second
  [client, docId, userId],
);

Connection management

Handle reconnection gracefully:

const client = new CloudSignal({
  preset: 'desktop',
  reconnectPeriod: 5000, // Reconnect after 5s
  connectTimeout: 30000, // Time out after 30s
});

client.on('reconnect', () => {
  console.log('Reconnecting...');
});

client.on('connect', () => {
  // Re-subscribe to topics after reconnect
  resubscribe();
});

On this page