Realtime

Broadcast

Send low-latency messages using the client libs, REST, or your Database.


You can use Realtime Broadcast to send low-latency messages between users. Messages can be sent using the client libraries, REST APIs, or directly from your database.

Subscribe to messages

You can use the Supabase client libraries to receive Broadcast messages.

Initialize the client

Go to your Supabase project's API Settings and grab the URL and anon public API key.

1
2
3
4
5
6
import { } from '@supabase/supabase-js'const = 'https://<project>.supabase.co'const = '<your-anon-key>'const = (, )

Receiving Broadcast messages

You can provide a callback for the broadcast channel to receive messages. This example will receive any broadcast messages that are sent to test-channel:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Join a room/topic. Can be anything except for 'realtime'.const = .('test-channel')// Simple function to log any messages we receivefunction () { .()}// Subscribe to the Channel .( 'broadcast', { : 'shout' }, // Listen for "shout". Can be "*" to listen to all events () => () ) .()

Send messages

Broadcast using the client libraries

You can use the Supabase client libraries to send Broadcast messages.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const = .('test-channel')/** * Sending a message before subscribing will use HTTP */ .({ : 'broadcast', : 'shout', : { : 'Hi' }, }) .(() => .())/** * Sending a message after subscribing will use Websockets */.(() => { if ( !== 'SUBSCRIBED') { return null } .({ : 'broadcast', : 'shout', : { : 'Hi' }, })})

Broadcast from the Database

You can send messages directly from your database using the realtime.send() function:

1
2
3
4
5
6
7
select realtime.send( jsonb_build_object('hello', 'world'), -- JSONB Payload 'event', -- Event name 'topic', -- Topic false -- Public / Private flag );

It's a common use case to broadcast messages when a record is created, updated, or deleted. We provide a helper function specific to this use case, realtime.broadcast_changes(). For more details, check out the Subscribing to Database Changes guide.

Broadcast using the REST API

You can send a Broadcast message by making an HTTP request to Realtime servers.

1
2
3
4
5
6
7
8
9
10
11
12
13
curl -v \-H 'apikey: <SUPABASE_TOKEN>' \-H 'Content-Type: application/json' \--data-raw '{ "messages": [ { "topic": "test", "event": "event", "payload": { "test": "test" } } ]}' \'https://<PROJECT_REF>.supabase.co/realtime/v1/api/broadcast'

Broadcast options

You can pass configuration options while initializing the Supabase Client.

Self-send messages

By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's self parameter to true.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const myChannel = supabase.channel('room-2', { config: { broadcast: { self: true }, },})myChannel.on( 'broadcast', { event: 'test-my-messages' }, (payload) => console.log(payload))myChannel.subscribe((status) => { if (status !== 'SUBSCRIBED') { return } myChannel.send({ type: 'broadcast', event: 'test-my-messages', payload: { message: 'talking to myself' }, })})

Acknowledge messages

You can confirm that the Realtime servers have received your message by setting Broadcast's ack config to true.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const = .('room-3', { : { : { : true }, },}).(async () => { if ( !== 'SUBSCRIBED') { return } const = await .({ : 'broadcast', : 'acknowledge', : {}, }) .('serverResponse', )})

Use this to guarantee that the server has received the message before resolving channelD.send's promise. If the ack config is not set to true when creating the channel, the promise returned by channelD.send will resolve immediately.

Send messages using REST calls

You can also send a Broadcast message by making an HTTP request to Realtime servers. This is useful when you want to send messages from your server or client without having to first establish a WebSocket connection.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const channel = supabase.channel('test-channel')// No need to subscribe to channelchannel .send({ type: 'broadcast', event: 'test', payload: { message: 'Hi' }, }) .then((resp) => console.log(resp))// Remember to clean up the channelsupabase.removeChannel(channel)

Trigger broadcast messages from your database

How it works

Broadcast Changes allows you to trigger messages from your database. To achieve it Realtime is directly reading your WAL (Write Append Log) file using a publication against the realtime.messages table so whenever a new insert happens a message is sent to connected users.

It uses partitioned tables per day which allows the deletion your previous messages in a performant way by dropping the physical tables of this partitioned table. Tables older than 3 days old are deleted.

Broadcasting from the database works like a client-side broadcast, using WebSockets to send JSON packages. Realtime Authorization is required and enabled by default to protect your data.

The database broadcast feature provides two functions to help you send messages:

  • realtime.send will insert a message into realtime.messages without a specific format.
  • realtime.broadcast_changes will insert a message with the required fields to emit database changes to clients. This helps you set up triggers on your tables to emit changes.

Broadcasting a message from your database

The realtime.send function provides the most flexibility by allowing you to broadcast messages from your database without a specific format. This allows you to use database broadcast for messages that aren't necessarily tied to the shape of a Postgres row change.

1
2
3
4
5
6
SELECT realtime.send ( to_jsonb ('{}'::text), -- JSONB Payload 'event', -- Event name 'topic', -- Topic FALSE -- Public / Private flag);

Broadcast record changes

Setup realtime authorization

Realtime Authorization is required and enabled by default. To allow your users to listen to messages from topics, create a RLS (Row Level Security) policy:

1
2
3
4
5
CREATE POLICY "authenticated can receive broadcasts"ON "realtime"."messages"FOR SELECTTO authenticatedUSING ( true );

See the Realtime Authorization docs to learn how to set up more specific policies.

Set up trigger function

First, set up a trigger function that uses realtime.broadcast_changes to insert an event whenever it is triggered. The event is set up to include data on the schema, table, operation, and field changes that triggered it.

For this example use case, we want to have a topic with the name topic:<record id> to which we're going to broadcast events.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CREATE OR REPLACE FUNCTION public.your_table_changes()RETURNS triggerSECURITY DEFINER SET search_path = ''AS $$BEGIN PERFORM realtime.broadcast_changes( 'topic:' || NEW.id::text, -- topic TG_OP, -- event TG_OP, -- operation TG_TABLE_NAME, -- table TG_TABLE_SCHEMA, -- schema NEW, -- new record OLD -- old record ); RETURN NULL;END;$$ LANGUAGE plpgsql;

Of note are the Postgres native trigger special variables used:

  • TG_OP - the operation that triggered the function
  • TG_TABLE_NAME - the table that caused the trigger
  • TG_TABLE_SCHEMA - the schema of the table that caused the trigger invocation
  • NEW - the record after the change
  • OLD - the record before the change

You can read more about them in this guide.

Set up trigger

Next, set up a trigger so the function runs whenever your target table has a change.

1
2
3
4
CREATE TRIGGER broadcast_changes_for_your_table_triggerAFTER INSERT OR UPDATE OR DELETE ON public.your_tableFOR EACH ROWEXECUTE FUNCTION your_table_changes ();

As you can see, it will be broadcasting all operations so our users will receive events when records are inserted, updated or deleted from public.your_table .

Listen on client side

Finally, client side will requires to be set up to listen to the topic topic:<record id> to receive the events.

1
2
3
4
5
6
7
8
const gameId = 'id'await supabase.realtime.setAuth() // Needed for Realtime Authorizationconst changes = supabase .channel(`topic:${gameId}`) .on('broadcast', { event: 'INSERT' }, (payload) => console.log(payload)) .on('broadcast', { event: 'UPDATE' }, (payload) => console.log(payload)) .on('broadcast', { event: 'DELETE' }, (payload) => console.log(payload)) .subscribe()