supabase-realtime
Original:🇺🇸 English
Translated
Subscribe to realtime changes in Supabase using WebSocket connections. Use for listening to database changes, presence tracking, and broadcast messaging.
10installs
Added on
NPX Install
npx skill4agent add nice-wolf-studio/claude-code-supabase-skills supabase-realtimeTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Supabase Realtime
Overview
This skill provides guidance for working with Supabase Realtime features. Realtime allows you to listen to database changes, broadcast messages, and track presence using WebSocket connections.
Note: Realtime operations require WebSocket support, which is more complex in bash. This skill focuses on practical patterns and examples using available tools.
Prerequisites
Required environment variables:
bash
export SUPABASE_URL="https://your-project.supabase.co"
export SUPABASE_KEY="your-anon-or-service-role-key"Additional tools:
- or
websocatfor WebSocket connectionswscat - for JSON processing
jq
Install websocat:
bash
# macOS
brew install websocat
# Linux
wget https://github.com/vi/websocat/releases/download/v1.12.0/websocat.x86_64-unknown-linux-musl
chmod +x websocat.x86_64-unknown-linux-musl
sudo mv websocat.x86_64-unknown-linux-musl /usr/local/bin/websocatWebSocket Connection
Connect to Supabase Realtime:
bash
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
# Extract WebSocket URL (replace https:// with wss://)
WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/')
# Connect to realtime
websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"Database Change Subscriptions
Subscribe to Table Changes
Listen to all changes on a table:
bash
#!/bin/bash
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/')
# Create subscription message
SUB_MESSAGE='{
"topic": "realtime:public:users",
"event": "phx_join",
"payload": {},
"ref": "1"
}'
# Connect and subscribe
echo "$SUB_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"Subscribe to specific events:
bash
# Listen for INSERT events only
SUB_MESSAGE='{
"topic": "realtime:public:users",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "INSERT",
"schema": "public",
"table": "users"
}
]
}
},
"ref": "1"
}'
echo "$SUB_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"Subscribe to UPDATE events:
bash
SUB_MESSAGE='{
"topic": "realtime:public:products",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "UPDATE",
"schema": "public",
"table": "products"
}
]
}
},
"ref": "1"
}'Subscribe to DELETE events:
bash
SUB_MESSAGE='{
"topic": "realtime:public:posts",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "DELETE",
"schema": "public",
"table": "posts"
}
]
}
},
"ref": "1"
}'Subscribe to all events (*, INSERT, UPDATE, DELETE):
bash
SUB_MESSAGE='{
"topic": "realtime:public:orders",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "*",
"schema": "public",
"table": "orders"
}
]
}
},
"ref": "1"
}'Filter Subscriptions
Listen to changes matching a filter:
bash
# Only listen to changes where status = 'active'
SUB_MESSAGE='{
"topic": "realtime:public:users",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "*",
"schema": "public",
"table": "users",
"filter": "status=eq.active"
}
]
}
},
"ref": "1"
}'Broadcast Messaging
Send Broadcast Message
Broadcast a message to a channel:
bash
#!/bin/bash
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/')
# Join channel first
JOIN_MESSAGE='{
"topic": "realtime:chat-room-1",
"event": "phx_join",
"payload": {
"config": {
"broadcast": {
"self": true
}
}
},
"ref": "1"
}'
# Broadcast message
BROADCAST_MESSAGE='{
"topic": "realtime:chat-room-1",
"event": "broadcast",
"payload": {
"type": "message",
"event": "new_message",
"payload": {
"user": "Alice",
"message": "Hello, World!"
}
},
"ref": "2"
}'
# Send messages
{
echo "$JOIN_MESSAGE"
sleep 1
echo "$BROADCAST_MESSAGE"
} | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"Listen to Broadcast Messages
Receive broadcast messages:
bash
# Join channel and listen
JOIN_MESSAGE='{
"topic": "realtime:chat-room-1",
"event": "phx_join",
"payload": {
"config": {
"broadcast": {
"self": false
}
}
},
"ref": "1"
}'
echo "$JOIN_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0"Presence Tracking
Track Presence
Join channel with presence:
bash
PRESENCE_MESSAGE='{
"topic": "realtime:lobby",
"event": "phx_join",
"payload": {
"config": {
"presence": {
"key": "user-123"
}
}
},
"ref": "1"
}'
# Track presence state
TRACK_MESSAGE='{
"topic": "realtime:lobby",
"event": "presence",
"payload": {
"type": "presence",
"event": "track",
"payload": {
"user_id": "123",
"username": "Alice",
"status": "online"
}
},
"ref": "2"
}'Untrack Presence
Leave presence:
bash
UNTRACK_MESSAGE='{
"topic": "realtime:lobby",
"event": "presence",
"payload": {
"type": "presence",
"event": "untrack"
},
"ref": "3"
}'Practical Patterns
Continuous Listener Script
bash
#!/bin/bash
# listen-to-changes.sh
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_KEY="your-anon-key"
WS_URL=$(echo "$SUPABASE_URL" | sed 's/https:/wss:/')
TABLE="users"
echo "Listening for changes on $TABLE table..."
# Subscribe to changes
SUB_MESSAGE='{
"topic": "realtime:public:'"$TABLE"'",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [
{
"event": "*",
"schema": "public",
"table": "'"$TABLE"'"
}
]
}
},
"ref": "1"
}'
# Listen continuously
echo "$SUB_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0" | \
while IFS= read -r line; do
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $line" | jq '.'
doneProcess Changes with Handler
bash
#!/bin/bash
# process-changes.sh
handle_insert() {
local record="$1"
echo "New record inserted:"
echo "$record" | jq '.payload.record'
# Your custom logic here
# Example: Send notification, update cache, etc.
}
handle_update() {
local old_record="$1"
local new_record="$2"
echo "Record updated:"
echo "Old: $(echo "$old_record" | jq -c '.')"
echo "New: $(echo "$new_record" | jq -c '.')"
}
handle_delete() {
local record="$1"
echo "Record deleted:"
echo "$record" | jq '.payload.old_record'
}
# Listen and process
websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0" | \
while IFS= read -r line; do
event_type=$(echo "$line" | jq -r '.payload.data.type // empty')
case "$event_type" in
"INSERT")
handle_insert "$(echo "$line" | jq '.payload.data')"
;;
"UPDATE")
handle_update \
"$(echo "$line" | jq '.payload.data.old_record')" \
"$(echo "$line" | jq '.payload.data.record')"
;;
"DELETE")
handle_delete "$(echo "$line" | jq '.payload.data')"
;;
esac
doneMulti-Table Listener
bash
#!/bin/bash
# listen-multiple-tables.sh
TABLES=("users" "posts" "comments")
for table in "${TABLES[@]}"; do
(
echo "Starting listener for $table"
SUB_MESSAGE='{
"topic": "realtime:public:'"$table"'",
"event": "phx_join",
"payload": {
"config": {
"postgres_changes": [{"event": "*", "schema": "public", "table": "'"$table"'"}]
}
},
"ref": "1"
}'
echo "$SUB_MESSAGE" | websocat "${WS_URL}/realtime/v1/websocket?apikey=${SUPABASE_KEY}&vsn=1.0.0" | \
while IFS= read -r line; do
echo "[$table] $line"
done
) &
done
waitMessage Format
Subscription Confirmation
json
{
"event": "phx_reply",
"payload": {
"response": {
"postgres_changes": [
{
"id": "12345",
"event": "*",
"schema": "public",
"table": "users"
}
]
},
"status": "ok"
},
"ref": "1",
"topic": "realtime:public:users"
}INSERT Event
json
{
"event": "postgres_changes",
"payload": {
"data": {
"commit_timestamp": "2023-01-01T12:00:00Z",
"record": {
"id": 123,
"name": "John Doe",
"email": "john@example.com"
},
"schema": "public",
"table": "users",
"type": "INSERT"
},
"ids": [12345]
},
"topic": "realtime:public:users"
}UPDATE Event
json
{
"event": "postgres_changes",
"payload": {
"data": {
"commit_timestamp": "2023-01-01T12:00:00Z",
"old_record": {
"id": 123,
"name": "John Doe"
},
"record": {
"id": 123,
"name": "Jane Doe"
},
"schema": "public",
"table": "users",
"type": "UPDATE"
}
}
}DELETE Event
json
{
"event": "postgres_changes",
"payload": {
"data": {
"commit_timestamp": "2023-01-01T12:00:00Z",
"old_record": {
"id": 123,
"name": "John Doe"
},
"schema": "public",
"table": "users",
"type": "DELETE"
}
}
}Alternative: REST Polling
For simpler use cases where WebSockets are impractical, consider polling:
bash
#!/bin/bash
# poll-changes.sh
source "$(dirname "${BASH_SOURCE[0]}")/../../scripts/supabase-api.sh"
LAST_TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
while true; do
# Get records created/updated since last check
new_records=$(supabase_get "/rest/v1/users?updated_at=gt.${LAST_TIMESTAMP}&order=updated_at.asc")
if [[ "$new_records" != "[]" ]]; then
echo "New changes detected:"
echo "$new_records" | jq '.'
# Update timestamp
LAST_TIMESTAMP=$(echo "$new_records" | jq -r '.[-1].updated_at')
fi
# Poll every 5 seconds
sleep 5
doneRealtime Configuration
Enable Realtime in Supabase Dashboard:
- Go to Database > Replication
- Enable replication for tables you want to listen to
- Choose which events to publish (INSERT, UPDATE, DELETE)
Row Level Security:
Realtime respects RLS policies. Users only receive changes for rows they have access to.
Limitations
- WebSocket connections require persistent connection management
- Bash is not ideal for WebSocket handling (consider Node.js/Python for production)
- Connection drops require reconnection logic
- Realtime is subject to connection limits based on your Supabase plan
Use Cases
Good for Realtime in bash:
- Development/debugging tools
- Simple monitoring scripts
- Log streaming
- Testing realtime functionality
Better in other languages:
- Production chat applications
- Complex presence tracking
- Multi-channel coordination
- Auto-reconnection requirements
API Documentation
Full Supabase Realtime documentation: https://supabase.com/docs/guides/realtime