Skip to content

Join a Session and Track Who's Online ​

Problem ​

You need to know which clients are connected to a session and display their identity (name, role, or custom metadata) in real time.

Solution ​

Join a session with identity metadata and subscribe to the clients or peers observable to track who is online. Use presence to share ephemeral state like cursor position or status.

Code ​

typescript
import { StarfishClient } from "@starfish/sdk";

const client = new StarfishClient({ server: "ws://localhost:4000" });
await client.connect();

await client.join("room-42", {
  name: "Alice",
  role: "editor",
  meta: { color: "#ff6b6b" },
});

// Track all connected clients (including self)
client.clients$.subscribe((clients) => {
  console.log("Online:", clients.map((c) => c.name));
});

// Track peers only (excludes self)
client.peers$.subscribe((peers) => {
  console.log("Peers:", peers.map((p) => p.name));
});

// Share your presence (e.g., cursor position)
client.presence.set({ cursor: { x: 100, y: 200 } });

// Watch all presence updates
client.presence$.subscribe((presenceMap) => {
  for (const [clientId, data] of presenceMap) {
    console.log(`${clientId} →`, data);
  }
});
python
from starfish import StarfishClient, StarfishClientOptions, JoinOptions

client = StarfishClient(StarfishClientOptions(server="ws://localhost:4000"))
await client.connect()

await client.join("room-42", JoinOptions(
    name="Alice",
    role="editor",
    meta={"color": "#ff6b6b"},
))

# Track all connected clients (including self)
client.clients.subscribe(
    lambda clients: print("Online:", [c.name for c in clients])
)

# Track peers only (excludes self)
client.peers.subscribe(
    lambda peers: print("Peers:", [p.name for p in peers])
)

# Share your presence (e.g., cursor position)
client.presence_set({"cursor": {"x": 100, "y": 200}})

# Watch all presence updates
client.presence.subscribe(
    lambda presence_map: [
        print(f"{cid} →", data)
        for cid, data in presence_map.items()
    ]
)
swift
import StarfishClient

let client = StarfishClient(options: StarfishClientOptions(
    server: URL(string: "ws://localhost:4000")!
))
try await client.connect()

try await client.join(session: "room-42", options: JoinOptions(
    name: "Alice",
    role: "editor",
    meta: ["color": AnyCodable("#ff6b6b")]
))

// Track all connected clients (including self)
Task {
    for await clients in client.clients {
        print("Online:", clients.map { $0.name ?? "?" })
    }
}

// Track peers only (excludes self)
Task {
    for await peers in client.peers {
        print("Peers:", peers.map { $0.name ?? "?" })
    }
}

// Share your presence (e.g., cursor position)
try client.presence.set(AnyCodable(["cursor": ["x": 100, "y": 200]]))

// Watch all presence updates
Task {
    for await presenceMap in client.presenceStream {
        for (clientId, data) in presenceMap {
            print("\(clientId) →", data)
        }
    }
}

Explanation ​

  • join(session, options) — connects to (or creates) a named session. The optional identity fields (name, role, meta) are visible to other clients.
  • clients$ / clients — an observable/stream of all connected clients, including yourself. Updates whenever someone joins or leaves.
  • peers$ / peers — same as clients but excludes the local client. Useful for rendering "other users" lists.
  • presence.set(payload) — sets your ephemeral presence data (max 8 KB). Other clients see this via the presence observable.
  • presence$ / presenceStream — a map from client IDs to their presence data. Updates in real time as peers change their presence.

Presence data is ephemeral — it is not persisted and disappears when a client disconnects. Use shared state if you need persistence.

Variations ​

Minimal join (no identity) ​

typescript
await client.join("my-session");
python
await client.join("my-session")
swift
try await client.join(session: "my-session")

Join without creating the session ​

Pass create: false to only join existing sessions — useful when the session must be created by a specific "host" client:

typescript
await client.join("host-session", { create: false });
python
await client.join("host-session", JoinOptions(create=False))
swift
try await client.join(session: "host-session", options: JoinOptions(create: false))