A Realtime instance holds a single WebSocket that handles all channel, subscription, and presence set communications. The SDK manages that socket for you. It connects lazily, reconnects with backoff, and repairs channel state after every drop, so most apps never have to worry about managing connection logic.
Connecting
Creating a client won’t immediately open the socket. Instead, the first operation that needs a connection, like a subscribe or publish, will automatically create the connection. Call connect() only when you want the socket warm before the first message. For example:
const realtime = new Realtime({ authCallback: fetchToken });
await realtime.connect(); // Eagerly connects to the service
console.log(realtime.getConnectionId(), realtime.getClientId());
getConnectionId() returns the server-assigned id for this connection and getClientId() returns the identity it authenticated as. Both are null until the first connect completes.
Connection states
Watch the connection lifecycle with connection.on, or await a specific state with connection.once:
realtime.connection.on((state, reason) => {
console.log(state, reason?.message);
});
await realtime.connection.once('connected');
| State | Meaning |
|---|---|
initialized |
Created locally, no connect attempted yet |
connecting |
The socket is opening and the auth handshake is in flight |
connected |
Authenticated and serving traffic |
disconnected |
Dropped unexpectedly, the SDK is retrying |
closing |
close() was called and the socket is shutting down |
closed |
Closed by close(), no retries |
failed |
A failure retrying cannot fix, like a rejected credential |
disconnected and failed differ by what happens next. disconnected means the SDK considers the drop temporary and keeps retrying on its own. failed means retrying would not help, for example a bad key or an expired token with no authCallback to mint a new one, so the SDK stops and sets its state to failed. An explicit connect() can be called from any stopped or failed state to put the connection back into a connecting state.
Reconnection
When the socket drops, the SDK reconnects with an exponential backoff, starting at 1 second after the first failure and doubling to a cap of 30 seconds. The delays are configurable, and autoReconnect: false turns retrying off entirely. For example:
const realtime = new Realtime({
authCallback: fetchToken,
initialReconnectDelayMs: 1_000,
maxReconnectDelayMs: 30_000,
});
Most apps won’t need to think about this reconnection lifecycle. Publishes made while disconnected or connecting are queued locally and flushed on connect, which is the queueMessages: true default described in Publish and subscribe.
What a reconnect restores
After the handshake completes, the SDK repairs everything the drop interrupted, in this order:
- Subscriptions. Every subscribed channel is re-attached. No listener re-registration is needed.
- Missed messages. Each channel resumes from the last sequence number it saw, so messages published during the gap replay to your listeners in order, as long as they are still within retention.
- Presence. Any presence this connection had entered is re-entered with the payload it last sent.
- Queued publishes. Buffered and unacknowledged publishes are resent. Each carries a stable client-assigned id, so a publish that was accepted just before the drop is deduplicated by the service rather than delivered twice.
Keep-alive
Connections periodically send heartbeats to the server with a keepAliveMs interval, so idle connections survive proxies and load balancers that cull quiet sockets.
Closing
await realtime.close();
close() shuts the socket down. Channels are released, no reconnect is attempted, and publishes still awaiting an ack reject with a “connection closed” error. Use it when a user signs out or during a test teardown. A closed client can connect again later with connect().
Limits
Each Realtime instance is one concurrent connection against your plan’s connection limit. Share one instance per page or process instead of constructing one per component, and remember that channels.get is already stable per name, so passing the client around is recommended.