Realtime

Subscribe to inserts, updates and deletes on your tables, filtered by row-level security, and add broadcast and presence.

Realtime pushes changes to your app the moment they happen, over one WebSocket. Subscribe to a table’s row changes, or open a room for broadcast messages and presence, such as live cursors and who is online.

Turn it on for a table#

On the database’s Data API tab, choose the table and switch on Realtime. The table must be exposed through the Data API and have a primary key.

From then on, every insert, update and delete on the table is streamed, whether it comes through the Data API, GraphQL, your server’s own connection or a migration.

Subscribe to row changes#

js
const feed = db.channel('changes:orders', { filter: 'status=eq.open' })
  .onChange(({ type, record, old }) => {
    // type: insert | update | delete
  })
  .subscribe();

// later
feed.unsubscribe();
dart
final feed = db.channel('changes:orders', 'status=eq.open')..subscribe();
feed.changes.listen((c) => print('${c.type} ${c.record}'));

// later
await feed.unsubscribe();
  • An insert or update arrives with the row as the subscriber is allowed to read it. Plexivo reads each changed row again as that subscriber, so your row-level security policies and the filter decide who receives it.
  • A delete arrives with the primary key of the row that was removed.
  • The filter is one condition in the Data API’s syntax, such as status=eq.open or owner=eq.<id>.

Broadcast and presence#

A room carries messages between the clients in it, and keeps track of who is there.

js
const room = db.channel('room:board-42')
  .onBroadcast('cursor', (p) => moveCursor(p))
  .onPresence(({ event, state }) => showWhoIsHere(state))
  .subscribe();

await room.ready();
room.sendBroadcast('cursor', { x: 10, y: 20 });
dart
final room = db.channel('room:board-42')..subscribe();
room.on('cursor').listen((p) => moveCursor(p));
room.presence.listen((p) => showWhoIsHere(p.state));

await room.ready();
room.sendBroadcast('cursor', {'x': 10, 'y': 20});

Presence lists each signed-in user by their user id, and each signed-out connection as anonymous, with the time they joined.

Rooms whose name starts with private:, such as room:private:team-7, admit signed-in users only.

Security#

  • Apps connect with the publishable key and, once signed in, the user’s token. The secret key is not accepted on the socket.
  • In a browser, the page must be on your Data API’s allowed web origin.
  • When a user’s token expires, their row-change and live-query channels stop at the next change; subscribe again with the refreshed session.

Limits#

  • Room names: up to 100 letters, digits and _ . : -.
  • Broadcast event names: up to 64 of the same characters; each message up to 32 KB.
  • One filter per row-change subscription.

Watch it in the console#

The Realtime tab shows each channel in use, with its connections, signed-in users, and broadcasts and changes per second, refreshed every 15 seconds.

For developers For a screen that shows the result of a query, a GraphQL live query sends the whole answer again whenever a row it reads changes.

Next steps#

Updated 27 October 2026