How to Turn Your MU Online Server Website Into an Installable PWA
Turn your MU Online server website into an installable Progressive Web App, with manifest, service worker, offline caching, and push notifications to boost player retention.
An MU Online server's website usually gathers the ranking, news, VIP/WCoin store, and account panel — but most are still consumed as a plain website, with no home screen icon and no offline functionality. Turning that site into a Progressive Web App (PWA) brings the experience closer to a native app
An MU Online server's website usually gathers the ranking, news, VIP/WCoin store, and account panel — but most are still consumed as a plain website, with no home screen icon and no offline functionality. Turning that site into a Progressive Web App (PWA) brings the experience closer to a native app: the player installs the icon on their phone, receives push notifications for events, and accesses pages already visited even without internet — all without going through an app store. This tutorial shows the full path — manifest, service worker, caching strategy, and notifications — applied to the reality of an MU server website.
Why it's worth it for an MU server
MU players mostly access the site from their phones to check the ranking, event schedule (Devil Square, Castle Siege, Chaos Castle), and store status. A PWA shortens the distance between "remembering the server exists" and "opening the site" down to a single tap on the home screen icon, and lets you re-engage inactive players via push notification when an important event is about to start — a retention advantage a regular site doesn't offer.
Mandatory prerequisite: HTTPS
Service workers are only registered in secure contexts. If your server's domain still serves the site over HTTP, set up a certificate (Let's Encrypt is free and widely supported by panels like cPanel and Plesk) before any other step in this tutorial — none of the PWA features will work without it.
Step 1 — Create the manifest.json file
The manifest describes how the site behaves when installed: name, icons, theme color, and display mode.
{
"name": "ViciadosMU - Servidor de MU Online",
"short_name": "ViciadosMU",
"start_url": "/?utm_source=pwa",
"display": "standalone",
"background_color": "#0d0d1a",
"theme_color": "#c9a24b",
"orientation": "portrait",
"icons": [
{ "src": "/assets/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/assets/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
]
}
display: standaloneremoves the browser's address bar, giving it a native app look.start_urlwith a UTM parameter lets you measure how many visits come from the installed app versus the regular browser.- Prepare icons in at least two resolutions (192x192 and 512x512), with a "maskable" version croppable to Android's different icon shapes.
Reference the manifest in the <head> of every page:
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#c9a24b">
Step 2 — Register the Service Worker
The service worker is the script that runs in the background in the browser and intercepts network requests, enabling caching and offline functionality.
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(reg => console.log('SW registered:', reg.scope))
.catch(err => console.error('SW registration failed:', err));
});
}
</script>
Step 3 — Define the caching strategy
Not all site content should be cached the same way. Split it by content type:
| Content type | Recommended strategy | Reason |
|---|---|---|
| CSS, JS, fonts, logos | Cache-first (uses cache, updates in the background) | Rarely changes, big speed gain |
| Ranking page | Network-first with cache fallback | Dynamic data, but useful to see the latest version offline |
| News page | Stale-while-revalidate | Shows what's cached quickly and updates silently |
| Login/panel/store | Network-only, no cache | Involves sensitive data and transactions, must never use stale data |
Step 4 — Implement sw.js
const CACHE_NAME = 'viciadosmu-v1';
const ASSETS_ESTATICOS = [
'/css/style.css',
'/js/app.js',
'/assets/icons/icon-192.png',
'/offline.html'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS_ESTATICOS))
);
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((chaves) =>
Promise.all(chaves.filter((c) => c !== CACHE_NAME).map((c) => caches.delete(c)))
)
);
});
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
// login/panel/store: never cache
if (url.pathname.startsWith('/painel') || url.pathname.startsWith('/loja')) {
return;
}
// static assets: cache-first
if (ASSETS_ESTATICOS.some((a) => url.pathname.endsWith(a))) {
event.respondWith(
caches.match(event.request).then((resp) => resp || fetch(event.request))
);
return;
}
// other pages: network-first with offline fallback
event.respondWith(
fetch(event.request).catch(() => caches.match(event.request).then((r) => r || caches.match('/offline.html')))
);
});
Create a simple offline.html page, with the server's logo and a message informing that the connection dropped — it appears when the player tries to access something not cached without internet.
Step 5 — Set up push notifications
Push notifications require a backend that manages subscriptions and a delivery service (Firebase Cloud Messaging is the most used with PHP/Node sites thanks to its generous free tier). The basic flow:
- The browser asks the player for notification permission (
Notification.requestPermission()). - The service worker subscribes to a push endpoint and receives a unique
subscription. - That subscription is saved in the panel's database, linked to the player's account.
- When an event starts (Castle Siege, special boss), your backend fires the notification to all active subscriptions.
self.addEventListener('push', (event) => {
const dados = event.data.json();
event.waitUntil(
self.registration.showNotification(dados.titulo, {
body: dados.corpo,
icon: '/assets/icons/icon-192.png',
badge: '/assets/icons/badge-72.png'
})
);
});
Step 6 — Test installability
Use Chrome DevTools (Application → Manifest and Application → Service Workers tabs) to confirm the manifest is valid and the service worker is active. Lighthouse (Lighthouse tab, PWA category) automatically audits installability criteria and points out what's missing — missing icons, lack of HTTPS, and an unreachable-offline start_url are the most common issues detected.
Behavior differences between Android and iOS
| Aspect | Android (Chrome) | iOS (Safari) |
|---|---|---|
| Install prompt | Automatic, "Add to Home Screen" banner | Manual, via Share button → Add to Home Screen |
| Push notifications | Natively supported | Only supported from iOS 16.4+, and only after manual installation |
| Maskable icon | Supported, cropped per the launcher | Ignored, uses the regular icon |
| Service worker update | Automatic in the background | May require reopening the installed app |
Metrics to track after launch
Monitor, in Google Analytics or an equivalent tool, the traffic filtered by the utm_source=pwa parameter defined in the manifest's start_url — this isolates how many visits come from players who installed the app. Also track the push notification opt-in rate and the return rate of players who received an event notification versus those who didn't install the PWA; this comparison usually quickly justifies the time invested in the implementation.
Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Install prompt doesn't appear | Site without HTTPS or invalid manifest | Fix the certificate and validate the manifest in DevTools |
| Login disappears or gets stuck with stale data | Service worker caching panel/store pages | Exclude those routes from the caching strategy in sw.js |
| Icon appears cropped on Android | Icon missing a maskable version | Add a 512x512 icon with purpose: maskable |
| Notifications don't arrive on iOS | iOS version older than 16.4 or app not manually installed | Guide the player to install via Safari before enabling notifications |
| Content stays outdated even after update | Old cache not invalidated | Bump the CACHE_NAME on every deploy to force cleanup |
PWA launch checklist
- HTTPS active across the entire site domain.
manifest.jsoncreated, referenced, and validated in DevTools.- 192x192 and 512x512 icons (including a maskable version) published.
- Service worker registered with a caching strategy per page type.
- Login/panel/store routes excluded from caching.
- offline.html page created and tested without a connection.
- Push notifications configured and tested on at least one real event.
- Lighthouse audit (PWA category) with no critical issues.
With the PWA live, the natural next step is to integrate push notifications into your automated event calendar, alerting players minutes before every Castle Siege or special boss. If the site is still in an early structural stage, it's worth reviewing the MU Online server creation guide to align the web infrastructure planning from the start. </content>
Frequently asked questions
Do I need to rewrite the entire site to turn it into a PWA?
No. A PWA is a layer added on top of the site you already have — you add a manifest.json file, register a service worker, and adjust a few HTTPS and icon details. The HTML, CSS, and backend stay the same.
Does the PWA work without internet?
Partially. With a well-configured service worker, pages and resources already visited (ranking, news, static items) become available offline via cache. Actions that depend on the database in real time, like login or store purchases, still require a connection.
Do I need to publish on Google Play or the App Store?
It's not mandatory. A PWA can be installed directly from the browser (Chrome, Edge, recent Safari on iOS) without going through an app store. Publishing on a store is optional and requires an extra packaging step (TWA for Android, for example).
How does a PWA help with player retention?
The icon installed on the phone's home screen reduces access friction — the player doesn't need to remember the URL or search the browser, they just tap the icon. Combined with push notifications, this significantly increases the return of inactive players to events and updates.
Do I absolutely need HTTPS?
Yes, no exceptions. Service workers and PWA installation only work over HTTPS connections (or localhost for development). If your server's site still runs on plain HTTP, that's the first prerequisite to solve.