Skip to content

Realtime Subscriptions

PocketBase includes realtime out of the box: your app can subscribe to a collection (or a single record) and receive create, update, and delete events the moment they happen. Under the hood it uses Server-Sent Events (SSE), which works through PocketBase Cloud’s HTTPS proxy with no extra setup.

Subscribe to a collection

// listen to all changes in the "messages" collection
pb.collection("messages").subscribe("*", (e) => {
  console.log(e.action); // "create" | "update" | "delete"
  console.log(e.record); // the affected record
});

A typical chat or feed UI applies the event directly to local state:

pb.collection("messages").subscribe("*", (e) => {
  if (e.action === "create") {
    messages.push(e.record);
  } else if (e.action === "update") {
    const i = messages.findIndex((m) => m.id === e.record.id);
    if (i >= 0) messages[i] = e.record;
  } else if (e.action === "delete") {
    messages = messages.filter((m) => m.id !== e.record.id);
  }
});

Subscribe to a single record

pb.collection("orders").subscribe("ORDER_ID", (e) => {
  updateStatusBadge(e.record.status);
});

Unsubscribe

Always clean up subscriptions when a component unmounts:

// remove a specific subscription
pb.collection("messages").unsubscribe("*");

// or remove all subscriptions on the client
pb.realtime.unsubscribe();

In React, pair subscribe/unsubscribe inside useEffect:

useEffect(() => {
  pb.collection("messages").subscribe("*", handleEvent);
  return () => pb.collection("messages").unsubscribe("*");
}, []);

Realtime respects your API rules

Events are only delivered for records the connected client is allowed to view according to the collection’s API rules. If a user can’t read a record via the REST API, they won’t receive realtime events for it either — so your ownership rules keep working with no extra code.

Subscriptions also support filters and expand options:

pb.collection("messages").subscribe(
  "*",
  (e) => { /* ... */ },
  {
    filter: "room = 'lobby'",
    expand: "author",
  }
);

Testing a subscription

With a subscription open in your app, trigger an event and watch it arrive.

Using the portal

Create, edit, or delete a record in the instance’s admin panel — every change made there is broadcast like any other.

Using the CLI

pbc admin use https://<instance-name>.pocketbasecloud.com
pbc admin login
pbc admin records create messages '{"text":"hello from the terminal","room":"lobby"}'

If nothing arrives, check the collection’s View rule before suspecting the connection — see Realtime respects your API rules.

Connection handling

The SDK maintains a single SSE connection per client and automatically reconnects and re-submits your subscriptions if the connection drops — useful on flaky mobile networks. You generally don’t need to handle reconnection yourself.

Realtime vs push notifications

Realtime subscriptions only reach clients that are connected right now — an open browser tab or a running app. They are not push notifications: when the app is closed or the phone is asleep, nothing is delivered and nothing queues up for later.

For notifications that reach a closed app, keep PocketBase as the trigger and send through a push provider (Firebase Cloud Messaging, APNs, Web Push, or a wrapper like Expo or OneSignal). A hook fires on the record change and calls the provider. For example, with Expo’s push API and a pushToken field on each user:

// pb_hooks/push.pb.js
onRecordAfterCreateSuccess((e) => {
  e.next();

  try {
    const recipient = e.app.findRecordById("users", e.record.get("recipient"));
    const token = recipient.get("pushToken");
    if (!token) return;

    $http.send({
      url: "https://exp.host/--/api/v2/push/send",
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ to: token, title: "New message", body: e.record.get("text") }),
      timeout: 10,
    });
  } catch (err) {
    e.app.logger().error("push failed", "error", String(err));
  }
}, "messages");

Use realtime for the live UI while the app is open, and push for everything else — most chat apps need both.

Next steps