Skip to main content

Realtime

Private Alpha

Realtime is currently in Private Alpha:

  • The feature is under active development and available to invited users only. Access must be requested.
  • APIs, parameters and console behavior may change in incompatible ways before general availability.
  • No SLA is provided. Do not use it in production workloads.

To request access or send feedback, contact your account manager or submit a ticket.

Realtime lets applications respond as soon as data or user state changes. You do not need to poll the database or build your own WebSocket service, connection management, reconnect logic, and message routing.

It is useful for chat, collaborative editing, online member lists, order status updates, live dashboards, and notifications. Browsers, Node.js and WeChat mini programs can use it through app.realtime() in the JavaScript SDK.

Core concepts​

Channels​

A channel is the basic unit for sending and receiving realtime events. Think of it as a named room, such as room:123. Clients in the same channel can receive the same broadcast messages and presence updates.

Channels can be public or private. Private channels use RLS policies on realtime.messages to check whether a client can join, send, and receive messages.

Three realtime capabilities​

CapabilityHow it worksTypical use casesGuide
BroadcastSends custom low-latency messages in a channel without first writing to a business tableChat, typing indicators, collaborative cursors, business notificationsBroadcast
PresenceTracks clients in a channel and their custom stateOnline lists, collaborator avatars, active pagesPresence
Postgres ChangesPushes an event after a PostgreSQL table receives an INSERT, UPDATE, or DELETEOrder status, message lists, live dashboardsPostgres CDC

The three capabilities share channels and WebSocket connections, but solve different problems:

  • Use Postgres Changes when the UI should update after data changes.
  • Use Broadcast for transient messages between clients.
  • Use Presence to show who is online and each member's state.
Difference from document database watch()

The document database uses collection.watch() to listen for collection changes. See Document database Realtime. app.realtime() handles channel messages, presence, and PostgreSQL table changes. The two do not replace each other.

Get started​

Before you begin, make sure that:

  1. Realtime is enabled for the current environment.
  2. Your application has initialized the CloudBase JavaScript SDK with a valid client access key.
  3. For Postgres Changes, the target table is in a publication and has the required table permissions and RLS policies.
  4. For private channels, realtime.messages has the required RLS policies.

The following example creates a channel, receives a Broadcast, and sends one:

import cloudbase from "@cloudbase/js-sdk";

const app = cloudbase.init({
env: "your-env-id",
accessKey: "your-publishable-key",
});

const realtime = app.realtime();
const channel = realtime.channel("room:123");

channel.on("broadcast", { event: "message-created" }, (payload) => {
console.log("received", payload);
});

channel.subscribe(async (status, error) => {
if (status === "SUBSCRIBED") {
await channel.send({
type: "broadcast",
event: "message-created",
payload: { text: "Hello" },
});
}

if (status === "CHANNEL_ERROR" || status === "TIMED_OUT") {
console.error(status, error);
}
});

When finished, unsubscribe and remove the channel so the connection is not left open:

await channel.unsubscribe();
await realtime.removeChannel(channel);

For initialization, partial imports, and connection management, see Quick start.

Configure and debug in the console​

Open an environment and go to PostgreSQL > Realtime. If Realtime is not enabled for the current environment, the page shows how to request access.

Manage table-change publications​

A publication is a database-level PostgreSQL object that determines which operations on which tables can produce change events.

Publications relate to database objects as follows:

  • A database can contain multiple schemas.
  • A schema organizes tables, views, and functions. Business tables are usually in public.
  • A publication can select tables from different schemas.
  • The INSERT, UPDATE, DELETE, and TRUNCATE switches apply to every table in the publication.

The system provides a cloudbase_realtime publication for Postgres Changes. The publication list shows the name, system ID, four operation switches, and the number of included tables. System-managed publications include an explanation. Do not manually delete their replication slots.

Select the table count to manage the publication's tables. The page lists all tables in the selected schema:

  • Switch on: the table is in the publication.
  • Switch off: the table is not in the publication and can be enabled here.
  • Switch disabled: the table belongs to a protected system schema such as realtime or auth and cannot be changed.

Publication changes take about 10 seconds to apply. When you enable a table, the system must also grant read access to the Realtime service role. If that grant fails, a client may subscribe successfully but receive no changes.

Verify the flow with the inspector​

The inspector is a Realtime client built into the console. It verifies channels, permissions, and event filters without requiring application code.

You can:

  • Join a public or private channel and leave it when finished.
  • Test RLS policies as an anonymous or authenticated user.
  • Listen separately for Broadcast, Presence, and Postgres Changes.
  • Filter Postgres Changes by schema, table, and row filter expression.
  • Inspect the message type, timestamp, and complete JSON payload.
  • Send a custom Broadcast and confirm that clients in the same channel receive it.

Before integrating Realtime into your application, test with the same identity and filters that the application will use.

Configure access policies​

Realtime has two independent authorization models:

  • Broadcast and Presence: private channels use RLS policies on realtime.messages.
  • Postgres Changes: subscriptions use the permissions and RLS policies on each business table.

Broadcast and Presence​

RLS is already enabled on realtime.messages. Do not run ALTER TABLE realtime.messages ENABLE ROW LEVEL SECURITY, and do not create or modify system tables in the protected realtime schema. You only need to create policies for realtime.messages under PostgreSQL > Access control > Policies.

The database operation in a policy determines which action it allows:

Database operationRealtime action
SELECTReceive Broadcast or Presence
INSERTSend Broadcast or publish Presence with track()

The realtime.messages.extension field identifies the message type:

  • Broadcast uses broadcast.
  • Presence uses presence.

The following policy allows authenticated users to receive Broadcast and Presence in room:123:

CREATE POLICY "authenticated can receive room events"
ON realtime.messages
FOR SELECT
TO authenticated
USING (
realtime.messages.extension IN ('broadcast', 'presence')
AND realtime.topic() = 'room:123'
);

Create a separate INSERT policy to let authenticated users send Broadcast and publish Presence in the same channel:

CREATE POLICY "authenticated can send room events"
ON realtime.messages
FOR INSERT
TO authenticated
WITH CHECK (
realtime.messages.extension IN ('broadcast', 'presence')
AND realtime.topic() = 'room:123'
);

realtime.topic() returns the channel that the client is trying to join. In a real application, avoid hard-coding every channel name. Instead, use a membership table to check whether the current user belongs to the requested channel. For example, if public.room_members contains topic and user_id:

EXISTS (
SELECT 1
FROM public.room_members
WHERE room_members.topic = realtime.topic()
AND room_members.user_id = (SELECT auth.uid())
)

Combine this expression with the extension condition to restrict each user to their own channels. You can also read custom JWT claims with the following expression and use a department, tenant, or role in the policy:

current_setting('request.jwt.claims', true)::json ->> 'your_claim'

After creating the database policies, configure the client channel as private:

const channel = realtime.channel("room:123", {
config: { private: true },
});

To require RLS authorization for every channel, turn off Allow public channels in Realtime settings. Once it is off, channels that do not set private: true are rejected.

Policy updates do not immediately affect existing connections

The service calculates and caches a client's permissions when it joins a channel. After you change a policy or remove a channel membership, a connected client may retain its previous access until it reconnects, sends a new JWT, or its current JWT expires.

Postgres Changes​

Postgres Changes does not use policies on realtime.messages. Each database change is checked against the RLS policies on the subscribed business table to decide whether the current subscriber may read that row.

For a client to receive table changes, make sure that:

  1. The target table is in the cloudbase_realtime publication.
  2. The subscriber role has SELECT access to the target table.
  3. RLS is enabled on the target table, with a policy that allows the current user to read the relevant rows.

Both public and private channels can subscribe to Postgres Changes. The channel's private setting does not bypass RLS on the business table.

Follow the principle of least privilege. Do not leave policies that allow every user to access every channel or row after debugging. For complete table permissions and RLS setup for Postgres Changes, see Database setup.

Adjust service settings​

Settings manage project-level runtime parameters, including:

  • Enabling or disabling Realtime.
  • Whether public channels are allowed.
  • Database pool sizes for authorization checks and Postgres Changes.
  • Maximum concurrent clients, total event rate, and Presence event rate.
  • Maximum payload size per message.

Saving settings disconnects active clients. Before changing pool sizes and limits, consider the database connection limit and actual traffic so Realtime does not compete with business SQL for resources.

Monitor and troubleshoot​

Realtime monitoring shows connected clients, Broadcast, Presence, Postgres Changes, channel joins, message payload size, database Broadcast lag, and RLS execution time for private channels.

API monitoring shows request volume, errors, response time, and popular paths for WebSocket connections and HTTP Broadcast. When an issue occurs, first determine whether it comes from connection setup, message delivery, database changes, or authorization, then use logs for further diagnosis.

Common issues:

SymptomWhat to check
The console says Realtime is not enabledConfirm that Realtime is enabled for the current environment
A Postgres Changes subscription failsConfirm that the table is in a publication and that the subscriber role has SELECT access
Subscription succeeds but no table changes arriveCheck the business table's RLS policies and wait for publication changes to apply
A private channel cannot be joined or cannot send messagesCheck the channel configuration and RLS policies on realtime.messages
Connections or messages are rejected under loadCheck pool sizes, concurrent client limits, and event-rate limits

For client states and error handling, see Quick start.