Brazil's biggest MU Online portal — since 2003
Tutorial Intermediate Web

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.

RO Rodrigo · Updated on Jan 21, 2018 · ⏱ 14 min read
Quick answer

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: standalone removes the browser's address bar, giving it a native app look.
  • start_url with 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 typeRecommended strategyReason
CSS, JS, fonts, logosCache-first (uses cache, updates in the background)Rarely changes, big speed gain
Ranking pageNetwork-first with cache fallbackDynamic data, but useful to see the latest version offline
News pageStale-while-revalidateShows what's cached quickly and updates silently
Login/panel/storeNetwork-only, no cacheInvolves 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:

  1. The browser asks the player for notification permission (Notification.requestPermission()).
  2. The service worker subscribes to a push endpoint and receives a unique subscription.
  3. That subscription is saved in the panel's database, linked to the player's account.
  4. 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

AspectAndroid (Chrome)iOS (Safari)
Install promptAutomatic, "Add to Home Screen" bannerManual, via Share button → Add to Home Screen
Push notificationsNatively supportedOnly supported from iOS 16.4+, and only after manual installation
Maskable iconSupported, cropped per the launcherIgnored, uses the regular icon
Service worker updateAutomatic in the backgroundMay 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

SymptomLikely causeFix
Install prompt doesn't appearSite without HTTPS or invalid manifestFix the certificate and validate the manifest in DevTools
Login disappears or gets stuck with stale dataService worker caching panel/store pagesExclude those routes from the caching strategy in sw.js
Icon appears cropped on AndroidIcon missing a maskable versionAdd a 512x512 icon with purpose: maskable
Notifications don't arrive on iOSiOS version older than 16.4 or app not manually installedGuide the player to install via Safari before enabling notifications
Content stays outdated even after updateOld cache not invalidatedBump the CACHE_NAME on every deploy to force cleanup

PWA launch checklist

  • HTTPS active across the entire site domain.
  • manifest.json created, 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.

RO
Founder & editor-in-chief

Rodrigo has run ViciadosMU since the portal's early days. A specialist in MU Online server creation and administration, game history and the evolution of the seasons — he wrote much of the archive before 2024.

Keep reading

Related articles