How to build a launcher with push notifications for your MU Online server
Build your own launcher for your MU Online server with a file update system and push notifications, alerting players in real time about events, server outages, and new versions.
A launcher is the first program a player opens before even seeing the MU Online login screen, which makes it an underused communication channel on most private servers. Beyond its basic function of checking and downloading client file updates, a modern launcher can keep a persistent connection to th
A launcher is the first program a player opens before even seeing the MU Online login screen, which makes it an underused communication channel on most private servers. Beyond its basic function of checking and downloading client file updates, a modern launcher can keep a persistent connection to the server and display real-time push notifications — warning about events about to start, unexpected server outages, or the release of a new season. This tutorial builds such a launcher with Electron, covering everything from file integrity checks to a WebSocket-based notification system.
General launcher architecture
A complete launcher has three components working together:
| Component | Responsibility |
|---|---|
| File checker | Compares the local client version with the version published on the server |
| Updater | Downloads and applies new or changed files |
| Notification client | Maintains a connection to the notification server and displays real-time alerts |
This tutorial focuses mainly on the third component, assuming the launcher already has (or will have) the first two basic functions implemented.
Prerequisites
- An existing launcher based on Electron, or willingness to build one from scratch with Node.js + Electron.
- A separate Node.js server (can run on the same VPS as the website) for the notifications backend.
- An authenticated admin panel, from where the team will trigger notifications.
- A valid SSL certificate on the domain used by the notifications backend (secure WebSocket,
wss://).
Step 1 — Structure the notifications backend
Create a dedicated Node.js service, separate from the main website application, responsible for keeping open launchers' WebSocket connections and broadcasting messages:
mkdir mu-notify-server && cd mu-notify-server
npm init -y
npm install ws express jsonwebtoken dotenv
// server.js
const { WebSocketServer } = require('ws');
const express = require('express');
const jwt = require('jsonwebtoken');
require('dotenv').config();
const app = express();
app.use(express.json());
const clients = new Set();
const wss = new WebSocketServer({ port: 8081 });
wss.on('connection', (ws) => {
clients.add(ws);
ws.on('close', () => clients.delete(ws));
});
// Authenticated endpoint used by the admin panel to trigger notifications
app.post('/broadcast', (req, res) => {
const auth = req.headers.authorization?.split(' ')[1];
try {
jwt.verify(auth, process.env.ADMIN_JWT_SECRET);
} catch {
return res.status(401).json({ error: 'unauthorized' });
}
const payload = JSON.stringify(req.body);
clients.forEach(ws => ws.readyState === 1 && ws.send(payload));
res.json({ sent: clients.size });
});
app.listen(3001, () => console.log('Broadcast API on port 3001'));
Step 2 — Authenticate the admin panel
The /broadcast endpoint should never be accessible without authentication — otherwise anyone could send fake notifications to every player, a clear phishing vector. Generate a long-lived JWT token exclusively for the admin team, store it securely in the panel, and validate it on every call to the endpoint.
Step 3 — Connect the launcher to the WebSocket
In the Electron main process, open the connection as soon as the launcher starts and keep automatic reconnection in case of a drop:
// main.js (Electron main process)
const WebSocket = require('ws');
const { Notification } = require('electron');
function connectNotifications() {
const ws = new WebSocket('wss://notify.yourserver.com');
ws.on('message', (data) => {
const msg = JSON.parse(data);
new Notification({
title: msg.titulo || 'Server notice',
body: msg.corpo,
icon: 'assets/icon.png'
}).show();
});
ws.on('close', () => {
setTimeout(connectNotifications, 5000); // tries to reconnect in 5s
});
ws.on('error', () => ws.close());
}
connectNotifications();
Step 4 — Display native operating system notifications
Electron's Notification module uses the native notification system of Windows (toast) or macOS, so the player receives the alert even with the launcher minimized in the system tray, as long as the process keeps running in the background.
Step 5 — Categorize notification types
Define categories in the payload sent by the backend, allowing the launcher to handle each type differently (icon, sound, priority):
| Category | Example use | Visual priority |
|---|---|---|
evento | "Invasion starts in 10 minutes" | High, with sound |
manutencao | "Server will enter maintenance at 10 PM" | High, persistent |
queda | "Server went down, the team is already checking" | Critical, sound + highlight |
novidade | "New season released, check out the changes" | Normal, no sound |
Step 6 — Build the notification trigger panel
In the admin panel (the same one used to manage accounts and rankings), add a simple form that sends the category, title, and message body to the /broadcast endpoint. Restrict this form to accounts with admin or senior moderator roles — triggering mass notifications should have the same level of access control as any sensitive administrative action.
Step 7 — Automatically detect server outages
Complementing manual triggering, set up a periodic check (every 1-2 minutes) that tests the connection to the ConnectServer/GameServer. If the check fails for two consecutive checks (avoiding a false positive from momentary instability), automatically fire a queda category notification to all connected launchers, without relying on an administrator being available to notice and manually warn players.
Step 8 — Test reconnection and resilience
- Force-close the notifications backend with the launcher open and confirm it automatically tries to reconnect.
- Send a test notification of each category and confirm it displays correctly on the operating system.
- Test the launcher minimized in the tray and confirm the native notification still appears.
- Simulate a GameServer outage and confirm the automatic detection fires the correct notification.
Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Launcher doesn't receive notifications | Invalid SSL certificate on wss:// | Renew the certificate and validate the WebSocket URL |
| Anyone can trigger a notification | /broadcast endpoint without authentication | Require a valid JWT from an admin account |
| Notification doesn't appear with launcher minimized | Background process terminated by the system | Configure the launcher to keep running in the tray |
| False server outage alarm | Single check with no confirmation | Require two consecutive failures before notifying |
| Reconnection creates multiple duplicate connections | No single-connection control per client | Close the previous connection before opening a new one |
Launch checklist
- Notifications backend running with secure WebSocket (
wss://). - Broadcast endpoint protected by admin JWT authentication.
- Launcher connecting automatically and reconnecting after a drop.
- Native operating system notifications tested on Windows.
- Notification categories defined and visually differentiated.
- Admin trigger panel restricted to authorized roles.
- Automatic server outage detection configured and tested.
With the launcher notifying players in real time, the next step is to integrate this channel with the rest of the communication ecosystem — connecting the same notification backend to the Discord bot and the events panel of the MU Online server, centralizing alerts in a single trigger point.
Frequently asked questions
Do I need to rewrite the launcher from scratch, or can I add push notifications to an existing one?
It depends on the current launcher's architecture. If it's already based on Electron or has a background process capable of maintaining a network connection, you can add a notifications module without rewriting the whole launcher. Very old launchers built in Delphi/VB may require more adaptation or even a partial rewrite.
Do push notifications work with the launcher closed?
It depends on the implementation. Operating system notifications (Windows toast) require at least one background process of the launcher to be running to receive them. A lighter alternative is to run only a minimal service that listens to the notification server and launches the full launcher when needed.
How do I prevent the notification system from being used to send spam or phishing?
Restrict sending notifications to an authenticated admin panel, never exposed publicly without login, and always sign/validate the message origin on the client side before displaying any notification, preventing a fake notification server from being injected into the launcher some other way.
What technology should I use for the notification server: WebSocket or HTTP polling?
WebSocket is more efficient for real-time notifications, since it keeps a connection open and avoids repeated requests. HTTP polling is simpler to implement and works well for low notification volumes (a few per hour), but generates more unnecessary traffic at scale.
Are the launcher's file update system and the push notification system the same thing?
No, but they complement each other. The file update system ensures the player's client has the correct version installed; push notifications alert the player about events and changes in real time, regardless of whether a file update is pending.