Real-time cursor tracking between multiple users, powered by CloudSignal MQTT over WebSocket.
- Install dependencies:
npm install
- Copy
.env.exampleto.env.localand configure your credentials:cp .env.example .env.local
- Start the dev server:
npm run dev
- Open
http://localhost:3000— two panels auto-connect as Alice and Bob
This demo uses preconfigured MQTT users (not token-based). Each user has credentials set via environment variables:
# CloudSignal WSS endpoint
NEXT_PUBLIC_CLOUDSIGNAL_WSS_URL=wss://connect.cloudsignal.app:18885/
# User credentials (create in CloudSignal dashboard under MQTT Users)
# Format: username@org_short_id
NEXT_PUBLIC_ALICE_USERNAME=alice@org_your_org_short_id
NEXT_PUBLIC_ALICE_PASSWORD=your_alice_password
NEXT_PUBLIC_BOB_USERNAME=bob@org_your_org_short_id
NEXT_PUBLIC_BOB_PASSWORD=your_bob_passwordAdd env vars following the pattern NEXT_PUBLIC_{NAME}_USERNAME and NEXT_PUBLIC_{NAME}_PASSWORD, then update src/app/page.tsx to include the new user panel.
Each user connects to CloudSignal via MQTT over WebSocket (WSS). Cursor positions are published to a shared topic at ~33Hz as small JSON payloads (~80 bytes). All connected users subscribe to the same topic and render remote cursors in real-time.
Browser A CloudSignal (VerneMQ) Browser B
───────── ────────────────────── ─────────
mousemove → publish ──WSS──▶ rooms/demo/cursors ──WSS──▶ subscribe → render
{x, y, name} remote cursor
Built-in measurements displayed in the UI:
- Latency: Time from publish to receive (ms)
- Connection time: Time from connect() to connected (ms)
- Message count: Total messages received
Create an ACL rule in your CloudSignal dashboard:
- Topic pattern:
rooms/# - Access: Publish + Subscribe
- Create a new project on Railway and connect your repo
- Set the Root Directory to
collaborate-demo(if this is inside a monorepo) - Add environment variables in the Railway service settings:
NEXT_PUBLIC_CLOUDSIGNAL_WSS_URLNEXT_PUBLIC_ALICE_USERNAMENEXT_PUBLIC_ALICE_PASSWORDNEXT_PUBLIC_BOB_USERNAMENEXT_PUBLIC_BOB_PASSWORD
- Railway auto-detects Next.js — it will run
npm run buildandnpm start - Assign a public domain under Settings > Networking > Public Networking
Note: Since credentials are in
NEXT_PUBLIC_env vars, they are embedded in the client bundle at build time. Railway must rebuild the app after changing these variables — a restart alone won't pick up changes. Use the Redeploy button or push a new commit.