← Back to Blog
PWAMobileThailand

Building PWAs for Thai Mobile Users

20 May 2026 · by Yunmin Shin

What Is a Progressive Web App?

A Progressive Web App (PWA) is a website that behaves like a native app. It can be installed on a user's home screen, work offline or on slow connections, send push notifications, and load instantly on repeat visits — without going through an app store.

For Thai businesses, PWAs offer a compelling alternative to native apps: no app store approval process, no separate iOS and Android codebases, and no asking users to download a 50MB app before they even know if they like your product. Users can install your PWA in two taps directly from the browser. For a clinic booking flow or a restaurant menu, that's the difference between a customer actually installing your app and bouncing off an app store listing they'll never revisit.

Why Do PWAs Make Sense in Thailand?

Thailand's smartphone market is Android-dominant, and device storage is a real constraint for users on lower-tier phones — a 6,000-12,000 baht Android device often ships with 64GB or less, and users are protective of that space. Many Thai users are also reluctant to install an app from a business they haven't established trust with yet; the friction of an app store listing, permissions screen, and a multi-megabyte download loses customers before they've even seen your product.

A PWA sidesteps this entirely. A first-time visitor experiences your app immediately in the browser — no gatekeeper, no download decision — and can install it to their home screen once they're actually engaged. For a clinic that wants return patients to rebook easily, or a restaurant that wants repeat diners opening straight to the menu instead of searching LINE or Google again, this lower barrier to "installation" is the whole point.

How Do You Build a PWA with Next.js?

The two essential PWA components are a Web App Manifest and a Service Worker.

Web App Manifest (public/manifest.json) defines how your app appears when installed:

{
  "name": "Bangkok Aesthetic Clinic",
  "short_name": "Clinic",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#0055ff",
  "icons": [
    { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
  ]
}

Reference it in your layout.tsx metadata:

export const metadata: Metadata = {
  manifest: "/manifest.json",
  themeColor: "#0055ff",
};

Service Worker enables offline functionality and caching. Use the next-pwa package to generate a service worker from your Next.js configuration without writing service worker code manually:

npm install next-pwa

Configure it in next.config.ts:

import withPWA from "next-pwa";
export default withPWA({
  dest: "public",
  disable: process.env.NODE_ENV === "development",
})(nextConfig);

How Does Offline Support Actually Work?

The service worker caches your app's assets on first load. When the user later opens the app without a connection — or with one so slow it might as well be offline — the service worker serves the cached assets instead of failing.

For Thai users in areas with patchy connectivity — provincial areas, the BTS underground between stations, or congested 4G in dense parts of Bangkok during rush hour — this is what keeps your app functional in situations where a regular server-rendered website would just show a browser error screen. A restaurant menu that's already cached loads instantly even in a dead zone; a clinic's list of treatments and prices stays readable even if the connection drops mid-session.

Be deliberate about what you cache versus what you always fetch fresh. Static assets (fonts, icons, the app shell) should be cached aggressively with long TTLs. Data that changes — appointment availability, order status, live pricing — should be fetched fresh when online and shown with a clear "last updated" or "offline" indicator when it isn't, rather than silently serving stale slot availability that could result in a double-booked appointment.

For write actions on a flaky connection — a patient submitting a booking request, a diner submitting an order — use the Background Sync API where supported, so the form submission queues locally and retries automatically once the connection returns, instead of failing silently and losing the request.

What About iOS?

Thailand's market skews Android, but a meaningful share of Bangkok's higher-spending demographic — exactly the customers an aesthetic clinic or upscale restaurant cares about — is on iPhone. iOS Safari's PWA support is real but more limited than Android Chrome: web push notifications require iOS 16.4+ and only work for apps already added to the home screen, storage quotas are tighter, and there's no beforeinstallprompt event at all — iOS users have to manually use the Share sheet's "Add to Home Screen" option.

Practically, this means: don't rely on push notifications as your only re-engagement channel for iOS users (LINE messages remain more reliable there), and add a lightweight, dismissible instructional banner for iOS Safari visitors showing them how to add the app manually, since the browser gives you no automatic prompt to hook into.

How Do You Implement an Install Prompt?

On Android/Chrome, browsers fire a beforeinstallprompt event when install criteria are met. Capture it and show your own custom install button rather than relying on the browser's default prompt:

window.addEventListener("beforeinstallprompt", (e) => {
  e.preventDefault();
  setInstallEvent(e);
  setShowInstallBanner(true);
});

Show the prompt at a meaningful moment — after a patient completes a booking, after a diner has browsed the menu for a while — not immediately on first load. An install prompt shown before the user has any reason to trust your business gets dismissed and often doesn't fire again for weeks.

How Do You Test This Properly?

Test on an actual mid-range Android device on real Thai mobile networks, not just Chrome DevTools' network throttling on a wired office connection. Behavior under "Slow 4G" in DevTools and behavior on an actual BTS platform or a soi with weak coverage are not the same thing. Lighthouse's PWA audit is a useful baseline check, but it won't catch the cache-invalidation bugs that only show up when real appointment data changes underneath a cached page.

Ready to Build Something Fast?

Get a free quote. We reply within 24 hours.

Ready to build something fast and scalable?

Get a free project quote. We reply within 24 hours.

Get a Free Quote →