tsguide(realtime): add guide to isolate client vs server issues (#49933)

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Troubleshooting docs addition.

## What is the current behavior?

This is troubleshooting documentation on how to diagnose missing
real-time messages and isolate whether it is a client-side or
server-side issue.

## What is the new behavior?

Adds a step-by-step troubleshooting guide for Realtime. This helps check
isolate connection and message delivery issues using:?

Realtime Inspector: to confirm server-side dispatch.
Browser DevTools: to confirm client-side receipt via WebSockets.



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Added a Supabase Realtime troubleshooting guide for isolating
server-side, client-side, and network-related subscription issues.
* Covers Realtime Inspector checks for subscriptions, broadcasts, and
presence; authorization and RLS validation; client configuration;
WebSocket traffic in browser developer tools; network connection
verification; and preparing diagnostic details for Support.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Ali Waseem <waseema393@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: krishnasaivandavasi <241076000+krishnasaivandavasi@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-09-17 15:02:21 -06:00
1 parent 64ab76262e
commit 51b6908236
1 file changed
+71
@@ -0,0 +1,71 @@
---
title = "Realtime: Isolating Server-Side vs. Client-Side Issues with Inspector and DevTools"
date_created = "2026-09-02T00:00:00+00:00"
topics = [ "realtime" ]
keywords = [ "postgres changes", "broadcast", "presence", "inspector", "devtools", "websocket", "subscribe" ]
---
Use this guide when a channel appears to subscribe successfully but the client consistently receives no `broadcast` messages, `presence` updates, or `postgres_changes` events. These steps help you determine whether the issue is on the server, in the client code, or in the client's network.
This guide does not cover events that arrive late or are dropped intermittently. Those symptoms may indicate a different issue, such as replication lag or an unstable connection.
## Step 1: Verify server-side delivery with Realtime Inspector
Open [Realtime Inspector](/dashboard/project/_/realtime/inspector) and select the feature you are debugging.
1. For `postgres_changes`, enter the same schema, table, event type, and filter used by your app. Connect as `postgres`, then perform the actual change that matches your event type and filter, for example inserting a row that satisfies the filter if you're testing `INSERT`. Check whether the event appears in Inspector.
2. Repeat the test as an authenticated user with the same role as your app. This can reveal RLS or authorization issues that are not visible when testing as `postgres`.
3. For `broadcast` or `presence`, test according to the channel type:
- **Public channels:** Authorization checks do not run, so test only as `postgres`.
- **Private channels:** Test as both `postgres` and an authenticated user. Use a session that matches the one sent by your app.
For `broadcast`, you can trigger the message directly from Inspector. For `presence`, Inspector can only observe the channel; the `track()` call has to come from your end, so open Inspector on the same channel name first, then trigger `track()` from your app and confirm that the state appears in Inspector.
**If the test fails as `postgres`:**
- For `postgres_changes`, see [Realtime: Postgres Changes Troubleshooting](/docs/guides/troubleshooting/realtime-postgres-changes-troubleshooting#step-1-is-the-table-in-the-realtime-publication). It covers publication membership and other server-side configuration.
- For `broadcast` or `presence`, the failure occurs before authorization. Verify that the trigger or send call is firing.
**If the test succeeds as `postgres` but fails as the authenticated user:**
- For `postgres_changes`, the issue is likely related to RLS. See [Realtime: Postgres Changes Troubleshooting](/docs/guides/troubleshooting/realtime-postgres-changes-troubleshooting#step-2-is-rls-quietly-blocking-the-row) for guidance on testing and fixing policies.
- For `broadcast` or `presence`, the issue is likely related to channel authorization on `realtime.messages` for that role. Review the [policy examples in the Realtime Authorization docs](/docs/guides/realtime/authorization?queryGroups=language&language=js#examples). Also check whether a complex policy is causing authorization checks to run slowly or time out.
**If both tests succeed:** The Realtime server and Postgres are working as expected. The issue is likely in the client or network path. Continue to Step 2.
## Step 2: Check the client configuration
Check for these common configuration issues:
- **`postgres_changes`:** Confirm that the filter, schema, table, and event type match. See the "Check the subscription code itself" section of [Realtime: Postgres Changes Troubleshooting](/docs/guides/troubleshooting/realtime-postgres-changes-troubleshooting#step-4-check-the-subscription-code-itself) for common mismatches.
- **`broadcast`:** Confirm that the sender and receiver use the same topic and event name.
- **`presence`:** Confirm that `track()` is called after the channel reaches `SUBSCRIBED` and that all clients use the same channel name.
Also make sure you are using a recent version of `@supabase/supabase-js` and, if pinned separately, `@supabase/realtime-js`. Older versions may contain bugs that cause events to be dropped.
If the configuration and package versions are correct but events still do not arrive, continue to Step 3.
## Step 3: Inspect connection traffic in browser developer tools
1. Open your application in Chrome, then open DevTools on that tab and go to the Network tab.
2. Trigger the action in your app that initiates the Realtime connection. Find the connection to `wss://<project-ref>.supabase.co/realtime/v1/websocket`.(Note: If your app connects on page load, refresh the page while DevTools is open).
3. Select the connection, then open the **Messages** tab.
4. Find the initial `phx_join` message and its corresponding `phx_reply`.
5. Keep the connection open for one or two minutes to capture heartbeats and other traffic.
6. Trigger the expected event, for example, insert a row, send a broadcast, or track presence.
Use the captured messages to determine what happened, then act accordingly:
- _Channel joined, but the server never sent the event:_ The subscription doesn't match what was tested in Step 1. Recheck it against Step 2.
- _Server sent the event, but the application didn't process it:_ The issue is in the client-side handler, not the subscription config. Check for a thrown error or rejected promise inside the callback that could be silently swallowing it.
- _WebSocket connection didn't complete at all:_ Continue to Step 4.
## Step 4: Check the network path
Confirm that the WebSocket request to `wss://.../realtime/v1/websocket` receives a `101 Switching Protocols` response.
If it does not, or if the console reports a TLS or certificate error, a firewall, proxy, or SSL-inspecting network appliance may be blocking the connection before it reaches Realtime.
Try testing the same app on a completely different network to confirm if the issue is network-specific.
If you still need help, [contact Support](/support) and include a description of the issue, relevant results of these tests, and the troubleshooting steps you've already tried. This information will help narrow down the cause.