By default, Broadcast and Presence are enabled for all projects.
By default, listening to database changes is disabled for new projects due to database performance and security concerns. You can turn it on by managing Realtime's replication.
You can receive the "previous" data for updates and deletes by setting the table's REPLICA IDENTITY to FULL (e.g., ALTER TABLE your_table REPLICA IDENTITY FULL;).
Row level security is not applied to delete statements. When RLS is enabled and replica identity is set to full, only the primary key is sent to clients.
Use AsyncStream or callbacks for listening to changes.
Examples
Listen to broadcast messages
let channel = await supabase.channel("room1")
let broadcastStream = await channel.broadcastStream(event: "cursor-pos")
await channel.subscribe()
Task \{
for await message in broadcastMessage \{
print("Cursor position received", message.payload)
\}
\}
Task \{
await channel.broadcast(
event: "cursor-pos",
message: [
"x": .double(.random(in: 0...1)),
"y": .double(.random(in: 0...1))
]
)
\}
Listen to broadcast messages using callback
let channel = await supabase.channel("room1")
let subscription = await channel.onBroadcast(event: "cursor-pos") \{ message in
print("Cursor position received", message.payload)
\}
await channel.subscribe()
await channel.broadcast(
event: "cursor-pos",
message: [
"x": .double(.random(in: 0...1)),
"y": .double(.random(in: 0...1))
]
)
// remove subscription some time later
subscription.remove()
Listen to presence updates
struct PresenceState: Codable \{
let username: String
\}
let channel = await supabase.channel("channelId")
let presenceChange = await channel.presenceChange()
await channel.subscribe()
Task \{
for await presence in presenceChange \{
let joins = try presence.decodeJoins(as: PresenceState.self)
let leaves = try presence.decodeLeaves(as: PresenceState.self)
\}
\}
// Send your own state
Task \{
try await channel.track(PresenceState(username: "John"))
\}
Listen to presence updates using callback
struct PresenceState: Codable \{
let username: String
\}
let channel = await supabase.channel("channelId")
let subscription = await channel.onPresenceChange() \{ presence in
let joins = try presence.decodeJoins(as: PresenceState.self)
let leaves = try presence.decodeLeaves(as: PresenceState.self)
\}
await channel.subscribe()
// Send your own state
try await channel.track(PresenceState(username: "John"))
// remove subscription some time later
subscription.remove()
Listen to all database changes
let channel = await supabase.channel("channelId")
let changeStream = await channel.postgresChange(AnyAction.self, schema: "public")
await channel.subscribe()
for await change in changeStream \{
switch change \{
case .delete(let action): print("Deleted: \(action.oldRecord)")
case .insert(let action): print("Inserted: \(action.record)")
case .select(let action): print("Selected: \(action.record)")
case .update(let action): print("Updated": \(action.oldRecord) with \(action.record)")
\}
\}
Listen to all database changes using callback
let channel = await supabase.channel("channelId")
let subscription = await channel.onPostgresChange(AnyAction.self, schema: "public") \{ change in
switch change \{
case .delete(let action): print("Deleted: \(action.oldRecord)")
case .insert(let action): print("Inserted: \(action.record)")
case .select(let action): print("Selected: \(action.record)")
case .update(let action): print("Updated": \(action.oldRecord) with \(action.record)")
\}
\}
await channel.subscribe()
// remove subscription some time later
subscription.remove()
Listen to a specific table
let channel = await supabase.channel("channelId")
let changeStream = await channel.postgresChange(
AnyAction.self,
schema: "public",
table: "users"
)
await channel.subscribe()
for await change in changeStream \{
switch change \{
case .delete(let action): print("Deleted: \(action.oldRecord)")
case .insert(let action): print("Inserted: \(action.record)")
case .select(let action): print("Selected: \(action.record)")
case .update(let action): print("Updated": \(action.oldRecord) with \(action.record)")
\}
\}
Listen to a specific table using callback
let channel = await supabase.channel("channelId")
let subscription = await channel.onPostgresChange(
AnyAction.self,
schema: "public",
table: "users"
) \{ change in
switch change \{
case .delete(let action): print("Deleted: \(action.oldRecord)")
case .insert(let action): print("Inserted: \(action.record)")
case .select(let action): print("Selected: \(action.record)")
case .update(let action): print("Updated": \(action.oldRecord) with \(action.record)")
\}
\}
await channel.subscribe()
// remove subscription some time later
subscription.remove()
Listen to inserts
let channel = await supabase.channel("channelId")
let insertions = await channel.postgresChange(
InsertAction.self,
schema: "public",
table: "users"
)
await channel.subscribe()
for await insert in insertions \{
print("Inserted: \(insert.record)")
\}
Listen to inserts using callback
let channel = await supabase.channel("channelId")
let subscription = await channel.onPostgresChange(
InsertAction.self,
schema: "public",
table: "users"
) \{ insert in
print("Inserted: \(insert.record)")
\}
await channel.subscribe()
// remove subscription some time later
subscription.remove()
Listen to updates
let channel = await supabase.channel("channelId")
let updates = await channel.postgresChange(
UpdateAction.self,
schema: "public",
table: "users"
)
await channel.subscribe()
for await update in updates \{
print("Updated: \(update.oldRecord) with \(update.record)")
\}
Listen to updates using callback
let channel = await supabase.channel("channelId")
let subscription = await channel.onPostgresChange(
UpdateAction.self,
schema: "public",
table: "users"
) \{ update in
print("Updated: \(update.oldRecord) with \(update.record)")
\}
await channel.subscribe()
// remove subscription some time later
subscription.remove()
Listen to deletes
let channel = await supabase.channel("channelId")
let deletions = await channel.postgresChange(
DeleteAction.self,
schema: "public",
table: "users"
)
await channel.subscribe()
for await deletion in deletions \{
print("Deleted: \(deletion.oldRecord)")
\}
Listen to deletes using callback
let channel = await supabase.channel("channelId")
let subscription = await channel.onPostgresChange(
DeleteAction.self,
schema: "public",
table: "users"
) \{ deletion in
print("Deleted: \(deletion.oldRecord)")
\}
await channel.subscribe()
// remove subscription some time later
subscription.remove()
Listen to row level changes
let channel = await supabase.channel("channelId")
let deletions = await channel.postgresChange(
DeleteAction.self,
schema: "public",
table: "users",
filter: "id=eq.1"
)
await channel.subscribe()
for await deletion in deletions \{
print("Deleted: \(deletion.oldRecord)")
\}
Listen to row level changes using callback
let channel = await supabase.channel("channelId")
let subscription = await channel.onPostgresChange(
DeleteAction.self,
schema: "public",
table: "users",
filter: "id=eq.1"
) \{ deletion in
print("Deleted: \(deletion.oldRecord)")
\}
await channel.subscribe()
// remove subscription some time later
subscription.remove()