Use Cases
Common patterns for using Notiway in your applications.
Regular Notifications
The simplest use case. Your backend publishes a notification when something happens, and the client displays it to the user in real time.
Examples: order shipped, new message received, payment confirmed, user mentioned in a comment.
sequenceDiagram
participant Backend
participant Notiway
participant Client
Backend->>Notiway: Publish notification
Notiway->>Client: Push over WebSocket
Client->>Client: Display to user
Producer side:
{
"id": "order-service-shipped-2025-01-15T10:00:00Z",
"type": "order-shipped",
"body": {
"orderId": "ORD-12345",
"message": "Your order has been shipped!"
},
"routing": {
"audienceType": 4,
"audienceValue": "user-123"
},
"metadata": {
"producer": "order-service",
"isPersisted": false
}
}Client side:
connection.on("order-shipped", (notification) => {
showToast(notification.body.message);
});Set isPersisted: true if you want offline users to receive the notification when they reconnect.
Notification Hub
A notification center where users can browse, read, and manage their notifications. This pattern uses persistence to store notifications and replay them on connect.
Examples: in-app notification inbox, activity feed, alert center.
sequenceDiagram
participant Backend
participant Notiway
participant Client
Backend->>Notiway: Publish persisted notification
Notiway->>Client: Push over WebSocket
Client->>Client: Add to notification list
Note over Client: User reconnects later
Client->>Notiway: Connect
Notiway->>Client: Replay missed notifications
Client->>Client: Populate notification list
Note over Client: User interacts
Client->>Notiway: MarkAsRead
Producer side: enable persistence and set a TTL.
{
"id": "billing-invoice-ready-2025-01-15",
"type": "invoice-ready",
"body": {
"invoiceId": "INV-789",
"amount": 149.99,
"currency": "USD"
},
"routing": {
"audienceType": 4,
"audienceValue": "user-123"
},
"metadata": {
"producer": "billing-service",
"isPersisted": true,
"persistedTTL": "2025-02-15T00:00:00Z"
}
}Client side: build a notification list and handle read/delete actions.
const notifications = [];
// Collect notifications (both live and replayed on connect)
connection.on("invoice-ready", (notification) => {
notifications.push(notification);
updateNotificationBadge(notifications.length);
});
// Mark as read when user opens the notification
async function onNotificationClick(notification) {
await connection.invoke("MarkAsRead", notification.audienceId, notification.id);
}
// Mark as deleted when user dismisses
async function onNotificationDismiss(notification) {
await connection.invoke("MarkAsDeleted", notification.audienceId, notification.id);
}
// Keep all devices in sync
connection.on("EventReadStatusChange", (change) => {
updateNotificationStatus(change.eventId, { isRead: change.isRead });
});
connection.on("EventDeletedStatusChange", (change) => {
updateNotificationStatus(change.eventId, { isDeleted: change.isDeleted });
});Status changes are synced across all of the user’s connected devices automatically.
Progress Events
Real-time progress tracking for long-running operations. The backend publishes progress updates to a specific user or connection, and the client renders a progress indicator.
Examples: file processing, deployment pipeline, data import/export, report generation.
sequenceDiagram
participant Backend
participant Notiway
participant Client
Client->>Backend: Start long-running task
Backend->>Client: Return task ID
loop Progress updates
Backend->>Notiway: Publish progress event
Notiway->>Client: Push over WebSocket
Client->>Client: Update progress bar
end
Backend->>Notiway: Publish completion event
Notiway->>Client: Push over WebSocket
Client->>Client: Show completed state
Producer side: send periodic progress updates.
{
"id": "import-service-progress-2025-01-15T10:00:05Z",
"type": "import-progress",
"body": {
"taskId": "import-456",
"progress": 45,
"status": "processing",
"message": "Processing row 4500 of 10000..."
},
"routing": {
"audienceType": 4,
"audienceValue": "user-123"
},
"metadata": {
"producer": "import-service",
"isPersisted": false
}
}Client side: register the handler before starting the task.
// Register handler for progress updates
connection.on("import-progress", (notification) => {
const { taskId, progress, status, message } = notification.body;
updateProgressBar(taskId, progress);
updateStatusText(taskId, message);
if (status === "completed") {
showCompletionMessage(taskId);
}
});
// Start the task
const response = await fetch("/api/imports", { method: "POST", body: data });
const { taskId } = await response.json();
showProgressBar(taskId);isPersisted: false to avoid storing transient updates.For progress scoped to a specific page or view, consider routing to the Connection audience (audienceType: 5) so only the tab that initiated the task receives updates.
System Announcements
Broadcast messages to all connected users at once. Ideal for platform-wide communication where every user needs to see the same message.
Examples: scheduled maintenance alerts, new feature announcements, policy changes, incident status updates.
sequenceDiagram
participant Admin
participant Notiway
participant Client A
participant Client B
participant Client N
Admin->>Notiway: Publish global announcement
par Broadcast
Notiway->>Client A: Push over WebSocket
Notiway->>Client B: Push over WebSocket
Notiway->>Client N: Push over WebSocket
end
Client A->>Client A: Display banner
Client B->>Client B: Display banner
Client N->>Client N: Display banner
Producer side: use Global routing to reach all connected clients.
{
"id": "platform-maintenance-2025-03-10T08:00:00Z",
"type": "system-announcement",
"body": {
"title": "Scheduled Maintenance",
"message": "The platform will be unavailable on March 12 from 02:00 to 04:00 UTC.",
"severity": "warning",
"actionUrl": "/status"
},
"routing": {
"audienceType": 1,
"audienceValue": "global"
},
"metadata": {
"producer": "admin-service",
"isPersisted": true,
"persistedTTL": "2025-03-12T04:00:00Z"
}
}Client side: display a persistent banner or modal.
connection.on("system-announcement", (notification) => {
const { title, message, severity, actionUrl } = notification.body;
showAnnouncementBanner({
title,
message,
severity, // "info" | "warning" | "critical"
actionUrl,
onDismiss: () => {
connection.invoke("MarkAsRead", notification.audienceId, notification.id);
}
});
});isPersisted: true so users who are offline see the announcement when they reconnect. Set the persistedTTL to match when the announcement becomes irrelevant (e.g., after the maintenance window ends).To scope announcements to a single tenant, use Tenant routing (audienceType: 2) instead of Global.
Live Dashboard
Push real-time data updates to dashboards and monitoring views. Instead of clients polling your API, your backend publishes state changes and Notiway pushes them instantly to every viewer.
Examples: analytics dashboards, order monitoring, server health panels, KPI trackers.
sequenceDiagram
participant Backend
participant Notiway
participant Dashboard A
participant Dashboard B
Note over Dashboard A,Dashboard B: Users open the dashboard
Dashboard A->>Notiway: Subscribe to "dashboard-ops" group
Dashboard B->>Notiway: Subscribe to "dashboard-ops" group
loop Data changes
Backend->>Notiway: Publish dashboard update
par Push to viewers
Notiway->>Dashboard A: Push over WebSocket
Notiway->>Dashboard B: Push over WebSocket
end
Dashboard A->>Dashboard A: Update charts
Dashboard B->>Dashboard B: Update charts
end
Note over Dashboard A: User leaves the page
Dashboard A->>Notiway: Unsubscribe from "dashboard-ops"
Client side: subscribe to the dashboard group when the user opens the page, unsubscribe when they leave.
// When the dashboard page mounts
await connection.invoke("Subscribe", {
audienceType: 3,
audienceValue: "dashboard-ops"
});
// Handle incoming updates
connection.on("dashboard-update", (notification) => {
const { metric, value, timestamp } = notification.body;
updateChart(metric, value, timestamp);
});
// When the user leaves the dashboard page
await connection.invoke("Unsubscribe", {
audienceType: 3,
audienceValue: "dashboard-ops"
});Producer side: publish updates to the group whenever metrics change.
{
"id": "metrics-service-dashboard-2025-03-10T10:05:00Z",
"type": "dashboard-update",
"body": {
"metric": "active-users",
"value": 1284,
"timestamp": "2025-03-10T10:05:00Z"
},
"routing": {
"audienceType": 3,
"audienceValue": "dashboard-ops"
},
"metadata": {
"producer": "metrics-service",
"isPersisted": false
}
}isPersisted: false since viewers always want the latest state, not old snapshots. If you need viewers to see the current state on connect, have your dashboard page fetch the initial data from your API and let Notiway handle the live updates after that.To scope the dashboard to a specific tenant, add tenantId to the routing and subscribe with the same tenant ID on the client.