---
title: Presence Detection
description: >-
  Build a presence detection system with Realtime Database: .info/connected,
  onDisconnect() (including cancel()), serverTimestamp() last-online stamps,
  .info/serverTimeOffset, and a multi-device presence sample.
next: /in-app-messaging/usage
previous: /database/offline-support
---
> ## Documentation Index
> Fetch the complete documentation index at: https://rnfirebase.io/llms.txt
> Use this file to discover all available pages before exploring further.

## Prerequisites

- `@react-native-firebase/app` installed and native config completed per [Getting Started](/) (Android `google-services.json`, iOS `GoogleService-Info.plist`, Expo config plugin, or React Native CLI setup). From v26, New Architecture is required for packages with a native bridge.
- `@react-native-firebase/database` installed: `npm install --save @react-native-firebase/database` or `yarn add @react-native-firebase/database`, then rebuild native apps (`cd ios && pod install` on iOS).
- `@react-native-firebase/auth` installed and a signed-in user available (`getAuth().currentUser`), because the examples below key presence by `uid`. Install Auth with `npm install --save @react-native-firebase/auth` or `yarn add @react-native-firebase/auth`, then rebuild native apps.
- Enable Realtime Database in the [Firebase Console](https://console.firebase.google.com/) and allow authenticated clients to write the `/online/{uid}` path in your security rules.

Realtime Database provides the ability to trigger events on the Firebase servers whenever a device is disconnected. This
could be whenever a user has no access to a network or when they quit the app.

One use-case using this functionality is to build a simple presence detection system, whereby we can hold a realtime list
of users currently online within our application. This could be useful when building a chat application
and you wish to view which of your users are currently online.

# Setup

To get started, we first need a location to store our online users.

To keep things simple we'll assume the user is authenticated (e.g. with [Firebase Authentication](/auth)) so we can use their unique user identifier.

Whenever the application opens, [write a new value](/database/usage#writing-data) on a reference node (e.g. `/online/:userId`):

```jsx
import { useEffect } from 'react';
import { getAuth } from '@react-native-firebase/auth';
import { getDatabase, ref, set } from '@react-native-firebase/database';

function App() {
  useEffect(() => {
    const user = getAuth().currentUser;
    if (!user) {
      console.log('No user is signed in; skip presence write');
      return undefined;
    }

    const userId = user.uid;
    const db = getDatabase();
    const reference = ref(db, `/online/${userId}`);

    // Set the /online/:userId value to true
    set(reference, true).then(() => console.log('Online presence set'));

    return undefined;
  }, []);

  return null;
}
```

Whenever the application boots and can connect to the remote server, the value will be written to the database indicating the user is online.

# On Disconnect

Next we need to remove the value when our user disconnects. Typically you would execute this functionality from the device
itself, however this presents a problem.

If the device suddenly goes offline, or is quit, the app can no longer execute code or connect to Firebase. Luckily, the
Realtime Database API provides a way to execute code on the Firebase servers whenever the connection between an app & server
is lost.

The `onDisconnect` function returns a new [`OnDisconnect`](https://reference.rnfirebase.io/_react-native-firebase/database/types/database/OnDisconnect.html) instance. This instance
provides functionality to remove or set data whenever a client disconnects. Using the
[`remove`](https://reference.rnfirebase.io/_react-native-firebase/database/types/database/OnDisconnect.html#remove) method we can remove the node on the database if the client disconnects:

```jsx
import { useEffect } from 'react';
import { getAuth } from '@react-native-firebase/auth';
import { getDatabase, ref, set, onDisconnect } from '@react-native-firebase/database';

function App() {
  useEffect(() => {
    const user = getAuth().currentUser;
    if (!user) {
      console.log('No user is signed in; skip presence and onDisconnect setup');
      return undefined;
    }

    const userId = user.uid;
    const db = getDatabase();
    const reference = ref(db, `/online/${userId}`);

    // Set the /online/:userId value to true
    set(reference, true).then(() => console.log('Online presence set'));

    // Remove the node whenever the client disconnects
    onDisconnect(reference)
      .remove()
      .then(() => console.log('On disconnect function configured.'));

    return undefined;
  }, []);

  return null;
}
```

The above code demonstrates a very simple but powerful way to track which users are currently online.

## Cancel On Disconnect

Call `cancel()` on an `OnDisconnect` instance to clear queued disconnect writes for that location (and its children) before they run:

```js
import { getDatabase, ref, onDisconnect } from '@react-native-firebase/database';

async function queueThenCancelDisconnect() {
  const presenceRef = ref(getDatabase(), 'disconnectmessage');
  const disconnect = onDisconnect(presenceRef);
  await disconnect.set('I disconnected');
  await disconnect.cancel();
  console.log('onDisconnect cancelled.');
}
```

# Connection state

Listen to `/.info/connected` to know when this client is connected to the Realtime Database backend:

```js
import { getDatabase, ref, onValue } from '@react-native-firebase/database';

const connectedRef = ref(getDatabase(), '.info/connected');
const unsubscribe = onValue(connectedRef, snapshot => {
  console.log(snapshot.val() === true ? 'connected' : 'not connected');
});

console.log('Connection listener attached:', typeof unsubscribe);
```

# Last online with server timestamps

Combine `onDisconnect` with `serverTimestamp()` to record when a client was last seen:

```js
import { getDatabase, ref, onDisconnect, serverTimestamp } from '@react-native-firebase/database';

async function trackLastOnline(userId) {
  const lastOnlineRef = ref(getDatabase(), `/users/${userId}/lastOnline`);
  await onDisconnect(lastOnlineRef).set(serverTimestamp());
  console.log('onDisconnect lastOnline stamp configured.');
}
```

# Server time offset

Listen to `/.info/serverTimeOffset` to read the millisecond skew the client adds to local time when estimating server time. Prefer `serverTimestamp()` for writes; use this offset mainly to detect large clock drift. For the React Native Firebase `getServerTime()` helper that wraps the same offset, see [Offline Support](/database/offline-support#server-time).

```js
import { getDatabase, ref, onValue } from '@react-native-firebase/database';

const offsetRef = ref(getDatabase(), '.info/serverTimeOffset');
const unsubscribe = onValue(offsetRef, snapshot => {
  const offset = snapshot.val();
  const estimatedServerTimeMs = Date.now() + offset;
  console.log('Estimated server time (ms):', estimatedServerTimeMs);
});

console.log('serverTimeOffset listener attached:', typeof unsubscribe);
```

# Sample presence app

Combine `/.info/connected`, per-device connection keys, `onDisconnect`, and `serverTimestamp()` into a multi-device presence system. Queue disconnect handlers before marking the connection online so a drop mid-setup cannot leave a stale "online" row:

```js
import {
  getDatabase,
  ref,
  onValue,
  push,
  onDisconnect,
  set,
  serverTimestamp,
} from '@react-native-firebase/database';

function attachPresence(userId) {
  const db = getDatabase();
  const myConnectionsRef = ref(db, `users/${userId}/connections`);
  const lastOnlineRef = ref(db, `users/${userId}/lastOnline`);
  const connectedRef = ref(db, '.info/connected');

  const unsubscribe = onValue(connectedRef, snapshot => {
    if (snapshot.val() !== true) {
      return;
    }

    const con = push(myConnectionsRef);
    onDisconnect(con).remove();
    set(con, true);
    onDisconnect(lastOnlineRef).set(serverTimestamp());
  });

  return unsubscribe;
}

const stopPresence = attachPresence('joe');
console.log('Presence listener attached:', typeof stopPresence);
```

When `users/{userId}/connections` has no children, that user has no active clients.
