TypeScript icon, indicating that this package has built-in type declarations

1.0.1 • Public • Published

Supabase Logo

Supabase Realtime Client

Send ephemeral messages with Broadcast, track and synchronize state with Presence, and listen to database changes with Postgres Change Data Capture (CDC).

Guides · Reference Docs · Multiplayer Demo


This client enables you to use the following Supabase Realtime's features:

  • Broadcast: send ephemeral messages from client to clients with minimal latency. Use cases include sharing cursor positions between users.
  • Presence: track and synchronize shared state across clients with the help of CRDTs. Use cases include tracking which users are currently viewing a specific webpage.
  • Postgres Change Data Capture (CDC): listen for changes in your PostgreSQL database and send them to clients.


Installing the Package

npm install @supabase/realtime-js

Creating a Channel

import { RealtimeClient } from '@supabase/realtime-js'

const client = new RealtimeClient(REALTIME_URL, {
  params: {
    apikey: API_KEY,
    eventsPerSecond: 10,

const channel = client.channel('test-channel', {})

channel.subscribe((status, err) => {
  if (status === 'SUBSCRIBED') {

  if (status === 'CHANNEL_ERROR') {
    console.log(`There was an error subscribing to channel: ${err.message}`)

  if (status === 'TIMED_OUT') {
    console.log('Realtime server did not respond in time.')

  if (status === 'CLOSED') {
    console.log('Realtime channel was unexpectedly closed.')


  • REALTIME_URL is 'ws://localhost:4000/socket' when developing locally and 'wss://<project_ref>.supabase.co/realtime/v1' when connecting to your Supabase project.
  • API_KEY is a JWT whose claims must contain exp and role (existing database role).
  • Channel name can be any string.
  • eventsPerSecond, or client-side rate limiting, enforces the number of events sent to the Realtime server uniformly spread across a second. The default is 10, which means that the client can send one event, whether that's Broadcast/Presence/Postgres CDC, every 100 milliseconds. You may change this as you see fit, and choose to disable by passing in a negative number, but note that the server's rate limiting will need to be updated accordingly. You can learn more about Realtime's rate limits here: https://supabase.com/docs/guides/realtime/rate-limits.


Your client can send and receive messages based on the event.

// Setup...

const channel = client.channel('broadcast-test', { broadcast: { ack: false, self: false } })

channel.on('broadcast', { event: 'some-event' }, (payload) =>

channel.subscribe(async (status) => {
  if (status === 'SUBSCRIBED') {
    // Send message to other clients listening to 'broadcast-test' channel
    await channel.send({
      type: 'broadcast',
      event: 'some-event',
      payload: { hello: 'world' },


  • Setting ack to true means that the channel.send promise will resolve once server replies with acknowledgement that it received the broadcast message request.
  • Setting self to true means that the client will receive the broadcast message it sent out.


Your client can track and sync state that's stored in the channel.

// Setup...

const channel = client.channel('presence-test', { presence: { key: '' } })

channel.on('presence', { event: 'sync' }, () => {
  console.log('Online users: ', channel.presenceState())

channel.on('presence', { event: 'join' }, ({ newPresences }) => {
  console.log('New users have joined: ', newPresences)

channel.on('presence', { event: 'leave' }, ({ leftPresences }) => {
  console.log('Users have left: ', newPresences)

channel.subscribe(async (status) => {
  if (status === 'SUBSCRIBED') {
    const status = await channel.track({ 'user_id': 1 })

Postgres CDC

Receive database changes on the client.

// Setup...

const channel = client.channel('db-changes')

channel.on('postgres_changes', { event: '*', schema: 'public' }, (payload) => {
  console.log('All changes in public schema: ', payload)

channel.on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, (payload) => {
  console.log('All inserts in messages table: ', payload)

channel.on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'users', filter: 'username=eq.Realtime' }, (payload) => {
  console.log('All updates on users table when username is Realtime: ', payload)

channel.subscribe(async (status) => {
  if (status === 'SUBSCRIBED') {
    console.log('Ready to receive database changes!')

Get All Channels

You can see all the channels that your client has instantiatied.

// Setup...



It is highly recommended that you clean up your channels after you're done with them.

  • Remove a single channel
// Setup...

const channel = client.channel('some-channel-to-remove')


  • Remove all channels
// Setup...

const channel1 = client.channel('a-channel-to-remove')
const channel2 = client.channel('another-channel-to-remove')




This repo draws heavily from phoenix-js.



Package Sidebar


npm i @zlq_bcxhs/realtime

Weekly Downloads






Unpacked Size

345 kB

Total Files


Last publish


  • bcxhs