|
| 1 | +--- |
| 2 | +title: 'Realtime: Broadcast Replay' |
| 3 | +description: '' |
| 4 | +author: eduardo_gurgel |
| 5 | +image: 2025-12-05-realtime-broadcast-replay/og.png |
| 6 | +thumb: 2025-12-05-realtime-broadcast-replay/thumb.png |
| 7 | +categories: |
| 8 | + - product |
| 9 | +tags: |
| 10 | + - realtime |
| 11 | +date: '2025-12-05' |
| 12 | +toc_depth: 2 |
| 13 | +--- |
| 14 | + |
| 15 | +Today we're releasing Broadcast Replay for Realtime - a powerful new feature that enables private channels to access messages that were sent earlier, ensuring your users never miss critical updates. |
| 16 | + |
| 17 | +## The Challenge: Missing Important Messages in Real-time Applications |
| 18 | + |
| 19 | +Building real-time applications comes with unique challenges. What happens when: |
| 20 | + |
| 21 | +- A user's connection drops momentarily? |
| 22 | +- Someone joins a collaborative session mid-way? |
| 23 | +- A page reload occurs during an important update? |
| 24 | +- Network interruptions cause missed messages? |
| 25 | + |
| 26 | +Previously, these scenarios meant lost context and degraded user experiences. Users would miss important messages sent while they were disconnected, and developers had to implement complex workarounds to maintain state consistency. |
| 27 | + |
| 28 | +## Introducing Broadcast Replay |
| 29 | + |
| 30 | +Broadcast Replay solves these challenges by allowing private channels to retrieve messages that were sent before a client connected or while they were disconnected. This feature integrates seamlessly with our existing [Broadcast from Database](/docs/guides/realtime/broadcast#broadcast-from-the-database) functionality, storing messages in the `realtime.messages` table for up to 3 days. |
| 31 | + |
| 32 | +It leverages the messages already stored when using Broadcast from Database. When you enable replay on a private channel, Realtime queries the partitioned `realtime.messages` table to retrieve historical messages based on your configuration. |
| 33 | + |
| 34 | +The replay configuration accepts two parameters: |
| 35 | + |
| 36 | +- **`since`** (required): Unix timestamp in milliseconds specifying the earliest point from which messages should be retrieved; |
| 37 | +- **`limit`** (optional): Number of messages to return (1-25, useful for preventing information overload). |
| 38 | + |
| 39 | +You can see Broadcast Replay in action at [https://multiplayer.dev](https://multiplayer.dev/), where the chat box demonstrates how users can access historical messages when joining or reconnecting to a conversation. |
| 40 | + |
| 41 | +## Real-World Use Cases |
| 42 | + |
| 43 | +### Chat Applications |
| 44 | + |
| 45 | +Display the most recent messages when users enter a chat room, providing immediate context without complex state management: |
| 46 | + |
| 47 | +```jsx |
| 48 | +const chatChannel = supabase.channel(`chat:${roomId}`, { |
| 49 | + config: { |
| 50 | + private: true, |
| 51 | + broadcast: { |
| 52 | + replay: { |
| 53 | + since: Date.now() - 300000, // Last 5 minutes |
| 54 | + limit: 25, // Show last 25 messages |
| 55 | + }, |
| 56 | + }, |
| 57 | + }, |
| 58 | +}) |
| 59 | +``` |
| 60 | + |
| 61 | +### Live Sports Updates |
| 62 | + |
| 63 | +Ensure fans never miss crucial moments, even after connection issues: |
| 64 | + |
| 65 | +```jsx |
| 66 | +const gameChannel = supabase.channel(`game:${matchId}:key-events`, { |
| 67 | + config: { |
| 68 | + private: true, |
| 69 | + broadcast: { |
| 70 | + replay: { |
| 71 | + since: matchStartTime, // Replay from match start |
| 72 | + limit: 20, // Show key events |
| 73 | + }, |
| 74 | + }, |
| 75 | + }, |
| 76 | +}) |
| 77 | +``` |
| 78 | + |
| 79 | +### Collaborative Editing |
| 80 | + |
| 81 | +Highlight recent changes in documents when users return: |
| 82 | + |
| 83 | +```jsx |
| 84 | +const docChannel = supabase.channel(`doc:${documentId}`, { |
| 85 | + config: { |
| 86 | + private: true, |
| 87 | + broadcast: { |
| 88 | + replay: { |
| 89 | + since: lastSeenTimestamp, // Changes since last visit |
| 90 | + limit: 15, |
| 91 | + }, |
| 92 | + }, |
| 93 | + }, |
| 94 | +}) |
| 95 | +``` |
| 96 | + |
| 97 | +## Working with Replayed Messages |
| 98 | + |
| 99 | +The triggered events are now enriched with metadata to recognise replayed messages. |
| 100 | + |
| 101 | +```jsx |
| 102 | +{ |
| 103 | + "event": "message", |
| 104 | + "meta": { |
| 105 | + "id": "55f92208-37c8-4c7b-930d-756f14586e55", |
| 106 | + "replayed": true |
| 107 | + }, |
| 108 | + "payload": { |
| 109 | + "content": "Hello world", |
| 110 | + "createdAt": "2025-11-12T15:41:22Z", |
| 111 | + "id": "3f0e4cdf-f886-4b2c-b132-1cedb5c55acc", |
| 112 | + "username": "supabasito" |
| 113 | + }, |
| 114 | + "type": "broadcast" |
| 115 | +} |
| 116 | +``` |
| 117 | + |
| 118 | +One can use the `meta.replayed` field to handle historical and live messages differently: |
| 119 | + |
| 120 | +```jsx |
| 121 | +// Broadcast callback receives meta field |
| 122 | +channel.on('broadcast', { event: 'chat_message' }, (payload) => { |
| 123 | + const chatMessage = payload.payload as ChatMessage |
| 124 | + // Render replayed messages with a different aspect |
| 125 | + chatMessage.replayed = payload?.meta?.replayed ?? false |
| 126 | + setMessages((current) => [...current, chatMessage]) |
| 127 | +}) |
| 128 | +``` |
| 129 | +
|
| 130 | +## Availability |
| 131 | +
|
| 132 | +Broadcast Replay is available today in **Public Alpha**. This feature requires: |
| 133 | +
|
| 134 | +- Supabase JavaScript client version 2.74.0 or later |
| 135 | +- Messages sent via [Broadcast from Database](/docs/guides/realtime/broadcast#broadcast-from-the-database) |
| 136 | +- Private channels with appropriate RLS policies |
| 137 | +
|
| 138 | +We're actively seeking feedback to refine this feature. If you encounter any issues or have suggestions, please [submit a support ticket](https://supabase.help/). |
| 139 | +
|
| 140 | +Check out our [documentation](/docs/guides/realtime/broadcast#broadcast-replay) for detailed implementation guides and more examples. |
| 141 | +
|
| 142 | +<div className="video-container"> |
| 143 | + <iframe |
| 144 | + className="w-full" |
| 145 | + src="https://www.youtube-nocookie.com/embed/scbQlEH3pRc" |
| 146 | + title="Introducing Realtime Broadcast Replay" |
| 147 | + allow="accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share" |
| 148 | + allowfullscreen |
| 149 | + /> |
| 150 | +</div> |
0 commit comments