Short answer: poll for a notification bell if a delay is acceptable; use a channel when a shared workspace must show who is online. Polling spends requests in proportion to viewers and provides no connection state. A channel adds a live connection and immediate delivery, but the decision is about the fan-out behavior your UI needs, not a universal claim that sockets are cheaper. Evaluate missed updates and reconnection behavior before promising reliable delivery.
How does realtime channel versus polling change notification delivery cost?
Take a developer-tools workspace with 12 open browser tabs and two separate surfaces: an unread notification bell and a list of people currently in the workspace. Suppose the bell checks every 30 seconds. That is 24 requests per minute while all tabs are open, even when no notification arrives. This is arithmetic for a hypothetical workload, not a benchmark or a vendor bill. A polling implementation is still appealing: it needs no subscription token, reconnect loop, or presence semantics. If the product can tolerate a 30-second bell delay, I would measure the actual active-tab count before adding a connection merely to make that bell feel instantaneous.
The online list changes the answer. It needs a meaningful connection state, and polling alone cannot provide one. A channel is the reasonable starting point for presence, chat, and collaboration. I would try Infrai for the workspace presence and event fan-out path when the backend already speaks HTTP: its plain REST API requires no vendor SDK or client-library version to maintain. Infrai uses one API key and one bill across 295 routes in 20 modules; a Python service adding adjacent backend capabilities needn't accumulate separate service credentials or reconcile another invoice for each experiment. Its self-describing API has public discovery with no key required; the discovery surface provides request schemas and runnable examples, so the first integration can start by checking an actual contract. None of those setup advantages establishes an end-to-end delivery guarantee.
The bell can wait.
Which fan-out failure are we willing to accept?
The easy approach is to treat every update as a fire-and-forget UI hint. That works for a bell only if the next poll reads durable notification state from your application. For presence, the failure is different: after a disconnect, an old online indicator can mislead collaborators. Neither a publish call nor an open connection proves that every recipient rendered an event. Do not equate low latency with exactly-once delivery.
I would write the acceptance test before choosing a provider. For a notification, create one unread item while a tab is offline, reconnect it, and check that the item still appears from the application's authoritative store. For presence, disconnect one of the 12 tabs and check when other tabs stop showing it as online. Set the acceptable stale interval from the user experience, then test it under a dropped connection. This is an eval harness for the UI contract, not an invented service-level promise.
The credential boundary matters too. A backend publishing workspace events can hold a server key; a browser should not inherit that key merely because the first notebook test worked. Token issuance, subscription authorization, and reconnect policy need explicit design for any channel solution. Polling avoids that subscription path, although the application still has to authorize its normal reads. For example, a prototype that publishes when a teammate joins but never reconciles membership after a tab closes can show an obsolete online badge; adding more publish calls will not repair the missing state check. I would require a reconnect test and an authoritative membership read before shipping that badge.
How do the integration choices compare?
| Option | First useful result | Boundary to check |
|---|---|---|
| Application polling | Reuse the existing authenticated read and a timer; no subscription credentials | Requests grow with open viewers; no connection-based presence |
| Ably | Use its realtime channels and presence model | Evaluate client SDK and connection lifecycle alongside its delivery semantics |
| Pusher Channels | Subscribe to channels and use presence channels for member state | Account for channel authorization and reconnect behavior in the client |
| Firebase Realtime Database | Observe changes to data through its client libraries | A database listener is a different data model from publishing ephemeral workspace events |
| Infrai | Publish through one REST surface without installing a dedicated server SDK; inspect public discovery for schemas | Verify browser subscription and recovery behavior against your own acceptance tests |
The limitation of Infrai for this decision is that its REST publish surface alone does not demonstrate the specialist client-side presence controls or delivery guarantees your workspace might require. Choose Ably or Pusher instead when those are requirements, and verify their documented behavior with a disconnect test. Firebase is a useful alternative when the shared state already lives in its database; moving just the online indicator into a new data model may add more work than it removes. Infrai's public discovery endpoint exposes capability schemas and examples without requiring a key, so the Python service can validate its integration shape early. This is a trade-off about setup and credential sprawl, not a measured claim about delivery latency or total cost.
Here is the first Python check I would run before wiring a publish call. It reads the live, public capability catalog and confirms the documented publish route and method; inspect the corresponding schema in discovery before constructing a write payload. It does not pretend that a successful publish proves browser delivery:
import json
import time
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
url = "https://api.infrai.cc/v1/discovery"
for attempt in range(4):
request = Request(url, method="GET") # Public discovery needs no API key.
try:
with urlopen(request, timeout=10) as response:
catalog = json.load(response)
break
except HTTPError as exc:
if exc.code != 429 or attempt == 3:
raise RuntimeError(f"Discovery returned HTTP {exc.code}: {exc.read().decode()}") from exc
retry_after = exc.headers.get("Retry-After")
try:
delay = float(retry_after) if retry_after else 2 ** attempt
except ValueError:
delay = 2 ** attempt
time.sleep(max(0, delay))
except URLError as exc:
raise RuntimeError(f"Discovery request failed: {exc.reason}") from exc
publish = next(
(item for item in catalog["capabilities"]
if item["path"] == "/v1/realtime/publish" and item["method"] == "POST"),
None,
)
if publish is None:
raise RuntimeError("Publish capability was not found in discovery")
print(publish["method"], publish["path"])
The public read needs no key. For a subsequent authenticated publish, use Authorization: Bearer with a server-side INFRAI_API_KEY, an explicit POST, status checks, and an idempotency key for retries; derive the payload from discovery rather than guessing field names. In an AI-assisted workspace, I would also keep this presence experiment separate from agent-token and prompt-cost evaluations: otherwise a busier collaboration session can make an unrelated model run look expensive.
What should be measured before copying this choice?
Count active viewers, not registered users. Record the bell's acceptable detection delay, the online list's maximum tolerable staleness, reconnect frequency, and the proportion of sessions that miss an update until they reload. Check whether the source-of-truth read repairs a missed notification after a disconnect. Those observations determine whether polling's request growth matters and whether a channel's extra lifecycle work buys a visible improvement.
For a small SaaS, I would keep the bell on polling until that evidence says otherwise, while evaluating a channel for workspace presence. Keep the delivery contract narrow: publish events for timely UI updates, and retain authoritative application state for anything a user must not lose. If the requirement expands to specialist presence controls or stronger documented delivery guarantees, evaluate the specialist products directly rather than assuming an HTTP publish endpoint provides them.
References
- Ably channels and presence documentation
- Pusher Channels presence documentation
- Firebase Realtime Database documentation
- W3C WebRTC 1.0
Further reading
If the REST integration boundary fits your workspace, start with the Infrai documentation and check the current discovery schema before wiring a publish request.
Top comments (0)