Use socket.js to connect any web page or React app to the notification service.
Include the script, connect, register your identity, and listen for messages.
Add the script tag to your page before your own code. It exposes NotificationSocket as a global.
<script src="https://notification.magicrunez.com/assets/socket.js"></script>
Add the same script tag to your index.html. NotificationSocket will be available as window.NotificationSocket once the script loads.
Pass the server URL to the constructor. The connection opens immediately. If it drops it retries automatically every 2 seconds.
const socket = new NotificationSocket('ws://notification.magicrunez.com');
Create the socket inside a useEffect so it opens on mount and closes cleanly on unmount. Call register() straight away so the server knows who this client is.
useEffect(() => {
const socket = new NotificationSocket('ws://notification.magicrunez.com');
socket.register(userId, userGroups, tenantId);
// attach event handlers here (see step 3)
return () => socket.destroy(); // close cleanly on unmount
}, []);
destroy() in your cleanup function.
It closes the connection and stops the auto-reconnect loop so the old socket doesn't keep running in the background.
Use socket.on(event, handler) to react to incoming messages.
In React, register handlers inside the same useEffect so they have access to your state setters.
const [connected, setConnected] = useState(false);
const [notifications, setNotifications] = useState([]);
useEffect(() => {
const socket = new NotificationSocket('ws://notification.magicrunez.com');
socket.register(userId, userGroups, tenantId);
socket.on('open', () => setConnected(true));
socket.on('close', () => setConnected(false));
socket.on('message', (msg) => {
setNotifications(prev => [msg, ...prev]);
});
return () => socket.destroy();
}, []);
The msg.type field describes the kind of message. Use it to update only the relevant slice of state.
socket.on('message', (msg) => {
if (msg.type === 'alert') {
setAlerts(prev => [msg, ...prev]);
}
if (msg.type === 'chat') {
setChatMessages(prev => [...prev, msg]);
}
});
| Event | When it fires |
|---|---|
| open | Connection established (including after a reconnect) |
| close | Connection dropped — socket will retry automatically |
| error | A WebSocket error occurred |
| connected | Server acknowledged the connection |
| registered | Server confirmed your identity |
| message | A message was routed to this client |
{
event: "message",
from: { tenantId: "…", userId: "42" },
to: [{ type: "user", id: "99" }],
type: "alert",
message: "Maintenance starting shortly",
data: "{\"startsIn\":300}" // always a JSON string
}
data is always a JSON string. Parse it with JSON.parse(msg.data) when you need the object.
Most apps only receive messages. If your app also needs to send them, use socket.send().
socket.send(
[
{ type: 'user', id: '99' },
{ type: 'group', id: ['admins', 'support'] }
],
'alert', // type / label
'Maintenance starting shortly', // human-readable text
{ startsIn: 300 } // optional data payload
);
Each recipient has a type of 'user' or 'group' and an id
that is either a single string or an array of strings for multiple recipients in one entry.
Messages sent before the connection is open are queued and delivered automatically once connected.
Store the URL in state and re-run the useEffect when it changes. The old socket is destroyed and a fresh one is created.
const [serverUrl, setServerUrl] = useState('ws://notification.magicrunez.com');
useEffect(() => {
const socket = new NotificationSocket(serverUrl);
socket.register(userId, userGroups, tenantId);
socket.on('message', (msg) => setNotifications(prev => [msg, ...prev]));
return () => socket.destroy();
}, [serverUrl]); // re-runs whenever the URL changes
Copy these interfaces into your project (e.g. notifications.d.ts) to get full type safety when working with the notification service.
/** A single recipient entry — target one or many ids of the same type */
type Recipient = {
type: 'user' | 'group';
id: string | string[];
};
/** Shape of a message you send (WebSocket or REST body) */
type OutboundMessage = {
to: Recipient[];
type: string; // e.g. 'alert' | 'chat' — your own labels
message: string; // human-readable text
data?: string; // optional JSON string — use JSON.stringify(payload)
};
/** Shape of a message the server routes to this client */
type InboundMessage = {
event: 'message';
from: { tenantId: string; userId: string };
to: Recipient[];
type: string;
message: string;
data: string; // always a JSON string — parse with JSON.parse(msg.data)
};
// Outbound — sent via socket.send() or the REST API
const body: OutboundMessage = {
to: [
{ type: 'user', id: '1' },
{ type: 'group', id: ['1', '8'] }
],
type: 'alert',
message: 'Server-side push',
data: JSON.stringify({ priority: 'high' }),
};
// Inbound — received via socket.on('message', …)
// {
// event: "message",
// from: { tenantId: "acme", userId: "42" },
// to: [{ type: "user", id: "1" }],
// type: "alert",
// message: "Server-side push",
// data: "{\"priority\":\"high\"}"
// }
const [notifications, setNotifications] = useState<InboundMessage[]>([]);
const [connected, setConnected] = useState<boolean>(false);
useEffect(() => {
const socket = new (window as any).NotificationSocket('ws://notification.magicrunez.com');
socket.register(userId, userGroups, tenantId);
socket.on('open', () => setConnected(true));
socket.on('close', () => setConnected(false));
socket.on('message', (msg: InboundMessage) => {
const parsed = msg.data ? JSON.parse(msg.data) : null;
setNotifications(prev => [{ ...msg, _parsed: parsed }, ...prev]);
});
// Sending a typed outbound message
const outbound: OutboundMessage = {
to: [{ type: 'user', id: '99' }],
type: 'alert',
message: 'Maintenance starting shortly',
data: JSON.stringify({ startsIn: 300 }),
};
socket.send(outbound.to, outbound.type, outbound.message, JSON.parse(outbound.data!));
return () => socket.destroy();
}, []);
NotificationSocket is loaded via a plain <script> tag and is not a typed npm package.
Cast it through (window as any).NotificationSocket, or add a minimal ambient declaration:declare const NotificationSocket: new (url: string) => any;