ENGINEERING

Real-Time Notifications Without Polling

Andres MuguiraFebruary 26, 20267 min read
SupabaseRealtimeNotifications
← Back to Blog
Summarize with AI

The Problem With Polling

The naive approach to notifications is polling. Every 5 seconds, the client sends a request to the server asking "do I have any new notifications?" The server queries the database, returns the results, and the client updates the UI. This works for a prototype. It does not work at scale.

Consider a workspace with 20 active users, each polling every 5 seconds. That is 240 database queries per minute just for notifications. Now multiply by the number of tables they might want changes from -- notifications, comments, deal updates, @mentions. You are looking at 1,000+ unnecessary queries per minute, most of which return zero results. The database is doing real work to tell you that nothing happened.

Polling is asking "are we there yet?" every five seconds for the entire car ride. WebSockets are the GPS telling you when you have arrived.

Supabase Realtime: The Architecture

SalesSheet runs on Supabase, which includes a Realtime service built on top of PostgreSQL's logical replication. When a row is inserted, updated, or deleted in any table with Realtime enabled, Supabase broadcasts the change to all subscribed clients over a WebSocket connection. No polling required.

Our notification architecture uses three Supabase Realtime channels:

Supabase Realtime architecture: 3 multiplexed channels (User Notifications, Workspace Activity, Presence) over a single WebSocket

Channel 1: User Notifications

Each user subscribes to a channel filtered by their user ID. When a notification row is inserted into the notifications table with their user ID as the recipient, they receive the payload instantly. The channel filter ensures users only receive their own notifications, enforced by Row Level Security (RLS) on the Supabase side.

Channel 2: Workspace Activity

All users in a workspace share a broadcast channel for workspace-wide events: new deals created, contacts imported, reports generated. These are not personal notifications -- they are ambient awareness events that keep the team in sync. We use Supabase's broadcast feature (not database changes) for these, because they are ephemeral and do not need to be stored.

Channel 3: Presence

Supabase Realtime includes a Presence feature that tracks which users are currently online. We use this to show green dots next to team members' avatars in the sidebar and to display "Sarah is viewing this contact" indicators when two users are looking at the same record. Presence syncs automatically -- when a user closes their browser tab, Supabase detects the WebSocket disconnection and removes them from the presence state.

The @Mention System

Our @mention system is the most notification-heavy feature in SalesSheet. Users can @mention teammates in comments on contacts, deals, and activities. When someone types @sarah in a comment, we need to:

  1. Parse the comment text to extract mention targets
  2. Resolve usernames to user IDs (with fuzzy matching for partial names)
  3. Create a notification record for each mentioned user
  4. Deliver the notification in real-time via the user's WebSocket channel
  5. Send a push notification if the user is not currently active
  6. Send an email digest if the user has been offline for more than 30 minutes

The parsing happens client-side for the autocomplete dropdown (so users see suggestions as they type), but the actual mention extraction and notification creation happens server-side in a Supabase Edge Function. This prevents users from spoofing mentions by manipulating the client payload.

@mention notification: bell icon with badge, notification dropdown showing "Sarah mentioned you in Acme deal"

Mention Autocomplete

When a user types @ in a comment field, we show a dropdown of workspace members. The dropdown filters as they type, using a fuzzy search that matches against first name, last name, and email. We pre-fetch the workspace member list on app load and cache it in memory, so the autocomplete is instant with no network request. The selected mention is rendered as a styled chip in the comment editor, using a contenteditable div with custom mention nodes.

Toast UX: The Notification Surface

Receiving a notification is only half the problem. Displaying it effectively is the other half. We use a toast notification system that appears in the bottom-right corner of the screen (bottom-center on mobile). Our toast system has specific design rules:

Toast notification stack: 3 toasts with different types (@mention, deal won, CSV import) and auto-dismiss timers

Handling Disconnection

WebSocket connections are fragile. Networks switch, laptops sleep, browsers crash. When the Supabase Realtime connection drops, we need to recover gracefully without missing any notifications. Our reconnection strategy works in three steps:

  1. Automatic reconnect -- Supabase's client library handles reconnection with exponential backoff. Typically, the connection re-establishes within 1-3 seconds.
  2. Gap fill -- on reconnection, we query the notifications table for any records created between the disconnection timestamp and the current time. This catches any notifications that were created while the WebSocket was down.
  3. State reconciliation -- we compare the local notification state with the server state and merge any differences. This handles edge cases where a notification was created and then immediately updated or deleted while the client was disconnected.

The disconnection timestamp is tracked using a lastSeen variable that updates every time we receive a Realtime event. If no events arrive for 30 seconds, we send a heartbeat ping. If the ping fails, we know the connection is dead and start the reconnection process before the user even notices.

Performance Numbers

After migrating from polling to Supabase Realtime, our numbers changed dramatically:

The latency improvement is the one users actually feel. When a teammate @mentions you, the toast appears before they have finished typing their next sentence. That immediacy transforms comments from an asynchronous communication channel into something that feels closer to a real-time chat. Teams that use @mentions heavily report that SalesSheet feels more like Slack than a traditional CRM, which is exactly the experience we wanted.

Real-time is not about technology. It is about team flow. When notifications arrive instantly, conversations happen in the CRM instead of in a separate chat app. Context stays where it belongs -- attached to the deal.

Try SalesSheet Free

No credit card required. Start selling smarter today.

Start Free Trial