Building real-time features usually means setting up WebSocket servers, managing connections, and handling reconnects. Supabase Realtime does all of this for you.
What is Supabase Realtime?
Supabase Realtime lets you listen to database changes, broadcast messages between clients, and sync presence (who is online) — all over WebSockets, all for free.
Three Realtime Features
1. Database Changes (Postgres Changes)
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
// Listen to ALL changes on the messages table
const channel = supabase
.channel('messages')
.on('postgres_changes', {
event: '*', // INSERT, UPDATE, DELETE
schema: 'public',
table: 'messages',
}, (payload) => {
console.log('Change:', payload.eventType, payload.new);
})
.subscribe();
// Listen to specific events
supabase
.channel('new-orders')
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'orders',
filter: 'status=eq.pending',
}, (payload) => {
showNotification(`New order: ${payload.new.id}`);
})
.subscribe();
2. Broadcast (Client-to-Client Messages)
// Send cursor positions, typing indicators, etc.
const channel = supabase.channel('room-1');
// Send
channel.send({
type: 'broadcast',
event: 'cursor',
payload: { x: 100, y: 200, userId: 'alice' },
});
// Receive
channel
.on('broadcast', { event: 'cursor' }, (payload) => {
updateCursorPosition(payload.payload);
})
.subscribe();
3. Presence (Who Is Online)
const channel = supabase.channel('online-users');
// Track your presence
channel.subscribe(async (status) => {
if (status === 'SUBSCRIBED') {
await channel.track({
userId: 'alice',
status: 'online',
lastSeen: new Date().toISOString(),
});
}
});
// Listen for presence changes
channel.on('presence', { event: 'sync' }, () => {
const state = channel.presenceState();
console.log('Online users:', Object.keys(state).length);
});
channel.on('presence', { event: 'join' }, ({ key, newPresences }) => {
console.log('User joined:', newPresences);
});
channel.on('presence', { event: 'leave' }, ({ key, leftPresences }) => {
console.log('User left:', leftPresences);
});
React Example: Live Chat
import { useEffect, useState } from 'react';
import { supabase } from './supabaseClient';
function LiveChat({ roomId }) {
const [messages, setMessages] = useState([]);
useEffect(() => {
// Load initial messages
supabase
.from('messages')
.select('*')
.eq('room_id', roomId)
.order('created_at')
.then(({ data }) => setMessages(data || []));
// Subscribe to new messages
const channel = supabase
.channel(`room-${roomId}`)
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'messages',
filter: `room_id=eq.${roomId}`,
}, (payload) => {
setMessages(prev => [...prev, payload.new]);
})
.subscribe();
return () => { supabase.removeChannel(channel); };
}, [roomId]);
const sendMessage = async (text) => {
await supabase.from('messages').insert({
room_id: roomId,
text,
user_id: (await supabase.auth.getUser()).data.user?.id,
});
};
return (
<div>
{messages.map(msg => <p key={msg.id}>{msg.text}</p>)}
<input onKeyDown={(e) => {
if (e.key === 'Enter') {
sendMessage(e.currentTarget.value);
e.currentTarget.value = '';
}
}} />
</div>
);
}
Free Tier Limits
- 200 concurrent connections
- 2 million messages/month
- Unlimited channels
Need real-time data feeds from the web? Check out my Apify actors — monitor websites and get instant updates. For custom solutions, email spinov001@gmail.com.
Top comments (0)