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 = supabase.channel("room1")
let broadcastStream = channel.broadcastStream(event: "cursor-pos")
await channel.subscribe()
Task \{
for await message in broadcastStream \{
print("Cursor position received", message)
\}
\}
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 = supabase.channel("room1")
let subscription = channel.onBroadcast(event: "cursor-pos") \{ message in
print("Cursor position received", message)
\}
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.cancel()
Listen to presence updates
struct PresenceState: Codable \{
let username: String
\}
let channel = supabase.channel("channelId")
let presenceChange = 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
try await channel.track(PresenceState(username: "John"))
Listen to presence updates using callback
struct PresenceState: Codable \{
let username: String
\}
let channel = supabase.channel("channelId")
let subscription = channel.onPresenceChange() \{ presence in
do \{
let joins = try presence.decodeJoins(as: PresenceState.self)
let leaves = try presence.decodeLeaves(as: PresenceState.self)
\} catch \{
// Handle decoding error
\}
\}
await channel.subscribe()
// Send your own state
try await channel.track(PresenceState(username: "John"))
// remove subscription some time later
subscription.cancel()
Listen to all database changes
let channel = supabase.channel("channelId")
let changeStream = 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 = supabase.channel("channelId")
let subscription = 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.cancel()
Listen to a specific table
let channel = supabase.channel("channelId")
let changeStream = 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 = supabase.channel("channelId")
let subscription = 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.cancel()
Listen to inserts
let channel = supabase.channel("channelId")
let insertions = 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 = supabase.channel("channelId")
let subscription = channel.onPostgresChange(
InsertAction.self,
schema: "public",
table: "users"
) \{ insert in
print("Inserted: \(insert.record)")
\}
await channel.subscribe()
// remove subscription some time later
subscription.cancel()
Listen to updates
let channel = supabase.channel("channelId")
let updates = 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 = supabase.channel("channelId")
let subscription = 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.cancel()
Listen to deletes
let channel = supabase.channel("channelId")
let deletions = 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 = supabase.channel("channelId")
let subscription = channel.onPostgresChange(
DeleteAction.self,
schema: "public",
table: "users"
) \{ deletion in
print("Deleted: \(deletion.oldRecord)")
\}
await channel.subscribe()
// remove subscription some time later
subscription.cancel()
Listen to row level changes
let channel = supabase.channel("channelId")
let deletions = 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 = supabase.channel("channelId")
let subscription = 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.cancel()