> ## Documentation Index
> Fetch the complete documentation index at: https://docs.larksh.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OnDisconnect

> Queue operations that run when a client disconnects

OnDisconnect operations let you write data to the server **when the client disconnects**. The server executes these writes even if the client crashes, closes the browser tab, or loses network without a clean goodbye.

This is the building block for presence systems, cleanup logic, and any scenario where you need the server to act on behalf of a client that's gone.

For a conceptual overview, see [OnDisconnect and presence](/platform/presence).

## Creating OnDisconnect operations

Call `ref.onDisconnect()` to get an `OnDisconnect` object, then chain a write method:

```typescript theme={null}
import { LarkDatabase, ServerValue } from "@lark-sh/client";

const db = new LarkDatabase("my-project/my-database", { anonymous: true });

// When this client disconnects, set "online" to false
await db.ref("users/alice/online").onDisconnect().set(false);
```

Every method returns a promise that resolves when the server has acknowledged and registered the operation.

## Methods

### `.set(value)`

Sets a value when the client disconnects:

```typescript theme={null}
await db.ref("users/alice/status").onDisconnect().set("offline");
```

### `.update(values)`

Performs a shallow merge when the client disconnects:

```typescript theme={null}
await db.ref("users/alice").onDisconnect().update({
  online: false,
  lastSeen: ServerValue.TIMESTAMP,
});
```

### `.remove()`

Deletes data when the client disconnects:

```typescript theme={null}
await db.ref("sessions/session-abc").onDisconnect().remove();
```

### `.setWithPriority(value, priority)`

Sets a value with a priority when the client disconnects:

```typescript theme={null}
await db.ref("queue/task-1").onDisconnect().setWithPriority("abandoned", 0);
```

### `.cancel()`

Cancels a previously registered OnDisconnect operation:

```typescript theme={null}
const onDisconnectRef = db.ref("users/alice/online").onDisconnect();

// Register it
await onDisconnectRef.set(false);

// Changed our mind — cancel it
await onDisconnectRef.cancel();
```

## Presence system

The most common use case for OnDisconnect is a presence system: tracking which users are currently online. Here's a complete implementation:

```typescript theme={null}
import { LarkDatabase, ServerValue } from "@lark-sh/client";

const db = new LarkDatabase("my-project/my-database", { token: "user-jwt-token" });

const uid = db.auth!.uid;
const userStatusRef = db.ref(`users/${uid}/status`);

// Watch connection state
db.ref(".info/connected").on("value", async (snapshot) => {
  if (!snapshot.val()) {
    return; // We're offline — the server will handle it
  }

  // We just connected (or reconnected).
  // Register what should happen when we disconnect.
  await userStatusRef.onDisconnect().update({
    online: false,
    lastSeen: ServerValue.TIMESTAMP,
  });

  // Now set ourselves as online
  await userStatusRef.update({
    online: true,
    lastSeen: ServerValue.TIMESTAMP,
  });
});
```

<Note>
  The order matters. Register the OnDisconnect operation **before** writing your online status. This avoids a race condition where you set `online: true` but the connection drops before the OnDisconnect is registered.
</Note>

### Why subscribe to `.info/connected`?

You might wonder why we don't just run the setup once. The reason is **reconnection**. If the client loses its connection and reconnects, previous OnDisconnect operations are cleared. By listening to `.info/connected`, you re-register the OnDisconnect handler every time the connection is re-established.

### Displaying presence

Other clients can subscribe to presence data:

```typescript theme={null}
// Watch a specific user's online status
const unsubscribe = db.ref("users/bob/online").on("value", (snapshot) => {
  if (snapshot.val()) {
    console.log("Bob is online");
  } else {
    console.log("Bob is offline");
  }
});

// Or watch all online users
const unsubAll = db.ref("users")
  .orderByChild("status/online")
  .equalTo(true)
  .on("value", (snapshot) => {
    const onlineUsers: string[] = [];
    snapshot.forEach((child) => {
      onlineUsers.push(child.key);
    });
    renderOnlineList(onlineUsers);
  });
```

## Cleanup on disconnect

Beyond presence, OnDisconnect is useful for any cleanup that should happen when a client leaves:

```typescript theme={null}
// Remove a player from a game lobby
await db.ref(`lobbies/lobby-1/players/${uid}`).onDisconnect().remove();

// Release a lock
await db.ref(`locks/document-42`).onDisconnect().remove();

// Mark a task as abandoned
await db.ref(`tasks/task-99/assignee`).onDisconnect().set(null);
```

<Warning>
  OnDisconnect operations run on the server, so they're limited to simple write operations (`set`, `update`, `remove`). You can't run transactions or custom logic in an OnDisconnect handler.
</Warning>
