Realtime
The Supabase Realtime channels the dashboard uses to stay live without polling.
The SurfacedBy web app does not poll for updates. It subscribes to a small set of Supabase Realtime channels scoped to your workspace, your domain, or your user, and receives push updates whenever the backend writes data you should see. These channels are an implementation detail of the dashboard today, but they are documented here because third-party integrations may want to subscribe directly.
Channels
Channels are scoped by workspace id, domain id, or user id. The dashboard subscribes to whichever channels are relevant to what is on screen.
| Topic | Channel format | Events |
|---|---|---|
| Scan lifecycle | scan-updates:{workspace_id} | scan_started, scan_progress, scan_completed, scan_failed |
| Tracked domains | domains:{workspace_id} | domain_added, domain_removed, domain_updated, competitor_suggested, competitor_accepted, competitor_dismissed, competitor_restored, competitor_deleted |
| Credits | credits:{workspace_id} | credits_purchased, credits_consumed, credits_refunded, balance_updated |
| Integrations | integrations:{workspace_id} | collector_heartbeat_received, collector_disconnected, collector_secret_generated, collector_secret_rotated, site_id_generated, site_id_rotated, site_id_revoked, webhook_secret_generated, webhook_secret_rotated, gsc_connected, gsc_disconnected, ga4_connected, ga4_disconnected, ga4_property_set |
| Workspace and membership | workspace:{workspace_id} | member_invited, member_joined, member_role_changed, member_removed, workspace_renamed, workspace_deleted, subscription_changed |
| Plans and action items | plans:{workspace_id} | plan_created, plan_updated, plan_deleted, item_created, items_bulk_created, item_updated, item_moved, items_reordered, item_deleted, item_step_toggled, item_event_logged |
| Analytics | analytics:{domain_id} | analytics_refreshed |
| AI traffic | tracking:{domain_id} | event_ingested and related ingest events |
| Content Checker | content-checks:{domain_id} | Crawl progress events |
| Opportunities | opportunities:{domain_id} | opportunity_dismissed, opportunity_restored, opportunities_bulk_dismissed, opportunity_resurfaced |
| Reports | reports:{domain_id} | report_generated, report_deleted, schedule_created, schedule_updated, schedule_deleted, schedule_paused, schedule_resumed, schedule_run_now, schedule_test_sent, schedule_sent, share_created, share_revoked |
| Notifications | notifications:{user_id} | notification_created, notification_read, unread_count_changed, milestone_earned |
| Profile | profile:{user_id} | profile_updated |
Workspace-scoped topics swap atomically when you change the active workspace, so a single subscription per topic is enough. Domain-scoped topics swap when you open a different domain inside the same workspace. User-scoped topics travel with you across workspaces, since they carry user-personal data (notifications, profile).
Delivery semantics
Realtime is best-effort. Events are delivered at most once. If the channel is disconnected during an event, the event is lost. That is fine for a live dashboard because the dashboard falls back to fetching fresh state on reconnect. It is not fine for durable integrations.
If you need guaranteed delivery, use outbound webhooks instead. Webhooks use at-least-once delivery with retries and a dead-letter queue.
Progress events are rate-limited
scan_progress and event_ingested are rate-limited to at most one message per scan or per domain per five seconds. That keeps the dashboard smooth without flooding subscribers with micro-updates.
Public API for realtime
A customer-facing realtime SDK is not part of the v1 release. If you have a use case that cannot be served by webhooks, reach out and we will document the direct subscription path.