Broadcast notifications
Introduction
Section titled “Introduction”Broadcast notifications deliver a toast in real time without waiting for a full page render. Use them when a background job finishes, an order ships, or any server-side event should pop a toast while the admin stays on the current page.
Orbit provides:
- A fluent
.broadcast(...)channel onNotification - A
BroadcastHubthat records payloads in-process (MemoryBroadcastHub) or fans them to a callback (CallbackBroadcastHub) - Panel
.live_broadcasts()which mounts GET{panel}/orbit-liveand binds the hub - Alpine
orbitLiveNotifications, which polls that URL and dispatches the browser eventorbit:broadcast
from almasix.orbit import Panelfrom almasix.orbit.notifications import Notification
Panel.make("admin").path("admin").live_broadcasts(polling="2s")
Notification.make() .title("Deploy finished") .success() .body("v1.4.2 is live on production.") .broadcast(user)

Sending broadcast notifications
Section titled “Sending broadcast notifications”.broadcast(user=None) sets the channel, enqueues on the notifier’s broadcast bag, and publishes to the process broadcast hub (the one .live_broadcasts() registered, or Notifier.use_hub(...)). .to_broadcast() only marks the channel for a later .send().
from almasix.orbit.notifications import LiveNotifier, MemoryBroadcastHub, Notification, set_notifier
hub = MemoryBroadcastHub()live = LiveNotifier().channel("orders").use_hub(hub)set_notifier(live)
Notification.make() .title("Processing complete") .success() .broadcast(user)

Inspect queued items with notifier.broadcast_queue() in tests.
Live notifier host
Section titled “Live notifier host”LiveNotifier.render_live() wraps the toast host and records channel names for the client:
from almasix.orbit.notifications import LiveNotifier
html = ( LiveNotifier() .channel("orders") .channel("App.Models.User.1") .render_live())Markup is <div class="or-live-notifier" data-channels="…" data-orbit-live-url="…" x-data="orbitLiveNotifications"> around the usual toast host. The panel shell does this automatically when .live_broadcasts() is on.


Broadcast hub
Section titled “Broadcast hub”MemoryBroadcastHub keeps an in-process log. CallbackBroadcastHub wraps another hub (memory by default) and calls your function on every publish — use that to forward events to Redis, a queue, or a websocket server.
from almasix.orbit.notifications import CallbackBroadcastHub, MemoryBroadcastHub
hub = CallbackBroadcastHub(lambda event: print(event["title"]))# or: MemoryBroadcastHub()

Live endpoint
Section titled “Live endpoint”.live_broadcasts() registers GET {panel}/orbit-live?since={cursor}. The JSON payload is { "events": [...], "cursor": N }. The Alpine host polls that URL (default 2s) and turns each event into orbit:broadcast.
from almasix.orbit import Panel
Panel.make("admin") .path("admin") .live_broadcasts(polling="2s")

You can still dispatch orbit:broadcast yourself from any other transport:
window.dispatchEvent( new CustomEvent("orbit:broadcast", { detail: { channel: "orders", title: "Order shipped", body: "#1042 left the warehouse.", status: "success", }, }),);That re-dispatches orbit:notify for the toast host — same shape as OrbitNotification.send(). Optional channel is filtered against data-channels when set.
Panel setup notes
Section titled “Panel setup notes”- Keep the panel toast host enabled (
.notifications()is on by default). - Call
.live_broadcasts()so the shell wraps the toast host and mounts/orbit-live. - Send with
.broadcast()from actions, jobs, or services. - For database rows that should appear immediately, prefer
.send_to_database(...)plus the bell endpoint — see Database notifications.
Related: Overview, Database notifications.