A 5-clinic pediatric practice across Mumbai's western suburbs — 28 doctors, ~6,400 monthly bookings, parents who book at 11 pm with one hand while a toddler sleeps on the other shoulder — came to us in July 2025 with a clear ask:
build us a native iOS + Android app. We shipped a Next.js PWA in 7 weeks for ₹4.6 lakh, a third of the native quote. Twelve weeks post-launch, install-to-booking conversion was 62%, and the practice cancelled their planned native build. This post is the cost math, the 3 PWA features that actually won parents over, and the one capability where we would still pick native.
5
Clinics across Mumbai's western suburbs
28
Pediatricians + 6 dentists
7 weeks
Discovery to live PWA
₹4.6L
Total fixed-price build
## TL;DR (60 Words)
We built a Next.js 14 PWA with service-worker offline caching, web push notifications, and an "Add to Home Screen" prompt. No app store. Total build cost ₹4.6 lakh against a native iOS+Android quote of ₹14.2 lakh. 12-week metrics: 62% install-to-booking conversion, 31% no-show drop, 11.4 day average from install to repeat booking. The one capability where native still wins: medical-record camera scan with on-device OCR.
## The Client (Specific Details)
-
Sector: Pediatric outpatient practice (vaccinations, sick visits, well-baby checks, paediatric dentistry)
-
Location: Mumbai western suburbs — Andheri, Bandra, Khar, Juhu, Versova
-
Size: 5 clinics, 28 doctors, 6 dentists, 84 staff total, ~6,400 monthly bookings
-
Stack on day 0: a 2018 Razorpay-tied web booking widget on WordPress, a single 11-year-old practice management system (PMS) running on a Windows VM at the Andheri HQ
-
Trigger: No-show rate had climbed to 24% in the 12 months to July 2025. The practice manager wanted reminder push notifications. The CEO wanted "an app, like Practo".
## Why This Matters Now
Web Push Notifications now work on iOS Safari (16.4+) for any installed PWA —
MDN's PWA notifications guide documents the cross-platform support. That single change in iOS 16.4 (April 2023) flipped the build-vs-PWA question for healthcare booking apps. Before iOS push, you needed a native app to send appointment reminders. Now you do not. For an Indian pediatric practice serving parents across iOS and Android, the PWA path saves ₹9.6 lakh up-front and ~₹3.4 lakh/year in store maintenance.
## The Cost Math (PWA vs Native iOS + Android)
| Cost line |
PWA (what we shipped) |
Native iOS + Android (the alt quote) |
| Build (one-time) |
₹4.6 lakh |
₹14.2 lakh (₹6.8L iOS + ₹7.4L Android) |
| App Store + Play Console fees (annual) |
₹0 |
₹8,200 + ₹2,300 one-time = ₹10,500 yr 1 |
| Store-listing copy + screenshots |
₹0 |
₹84,000 (designer + copywriter) |
| Maintenance (annual) |
₹54,000 (one stack) |
₹2,40,000 (two stacks, OS upgrades) |
| Time-to-launch |
7 weeks |
14–18 weeks (incl. store reviews) |
| Install friction (parent's POV) |
Add to Home Screen, 0 reviews |
App Store search, 60+ MB download |
| 3-year total cost of ownership |
₹6.22 lakh |
₹22.5 lakh |
The cost gap closes if you have a 50,000+ install base needing app-store discoverability or you need a capability the web cannot give you (continuous Bluetooth, background audio, deep iOS integrations). For a pediatric practice with a known patient base of 23,000 families, the discoverability argument was moot. Parents come to the practice's website. They install from there.
## The 3 PWA Features That Won Parents Over
PN
Web Push Reminders (24h, 2h, 30min before)
Three reminders per appointment via web-push (VAPID + service worker). Worked on iOS Safari 16.4+ and all Android Chrome. No-show rate fell from 24% to 16.7% in 8 weeks. The 24h reminder also includes a one-tap "reschedule" link.
OF
Offline Vaccine Card
A child's vaccination history is cached in the service worker. Parents at the airport, in a basement OPD, on a train can pull up the card with no network. Used 3.4x more than the live booking screen in week 8 onwards.
A2H
Add-to-Home-Screen Prompt at the Right Moment
We do not show the install prompt on first visit. We show it after the second successful booking. Install-acceptance rate jumped from 18% (first-visit prompt) to 71% (post-second-booking). The prompt also explains the offline vaccine card benefit.
## The Architecture
FE
Next.js 14 App Router + Tailwind + Workbox service worker
PN
VAPID web-push (self-hosted, no Firebase) + iOS 16.4+ verified
DB
PostgreSQL 16 + Prisma + per-clinic doctor-availability calendar
PMS
PMS write-through API (custom shim, syncs every 90 sec)
We followed
Next.js's official PWA guide for the manifest + service worker plumbing. Web push is self-hosted (no Firebase) using the standard VAPID keys + node web-push library. The Practice Management System (PMS) is the source of truth for clinical data; our PWA writes appointments through a thin shim and reads back authoritative state every 90 seconds.
## The Service Worker (The 80-Line File That Earns Its Keep)
// /public/sw.js - the Workbox-generated worker we ship
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { NetworkFirst, CacheFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';
precacheAndRoute(self.__WB_MANIFEST);
// Vaccine card data: cache aggressively, network-first only when fresh needed
registerRoute(
({ url }) => url.pathname.startsWith('/api/vaccine-card/'),
new NetworkFirst({
cacheName: 'vaccine-card',
networkTimeoutSeconds: 3,
plugins: [
new ExpirationPlugin({ maxEntries: 50, maxAgeSeconds: 30 24 60 * 60 }),
],
})
);
// Doctor photos and clinic images: long-lived, cache-first
registerRoute(
({ request }) => request.destination === 'image',
new CacheFirst({
cacheName: 'images',
plugins: [
new ExpirationPlugin({ maxEntries: 200, maxAgeSeconds: 90 24 60 * 60 }),
],
})
);
// Web push handler
self.addEventListener('push', (event) => {
const data = event.data.json();
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icons/icon-192.png',
badge: '/icons/badge-72.png',
tag: appt-${data.appointmentId},
actions: [
{ action: 'reschedule', title: 'Reschedule' },
{ action: 'dismiss', title: 'OK' },
],
data: { appointmentId: data.appointmentId, url: data.url },
})
);
});
// Notification click handler with action routing
self.addEventListener('notificationclick', (event) => {
event.notification.close();
const target = event.action === 'reschedule'
? /appointment/${event.notification.data.appointmentId}/reschedule
: event.notification.data.url;
event.waitUntil(clients.openWindow(target));
});
Three things to notice. The vaccine card uses NetworkFirst with a 3-second timeout — the parent gets the latest data when network is good, but a slightly stale copy when the network is bad. Images are CacheFirst (cosmetic, fine to be stale). The push handler honours iOS 16.4's strict requirement that
showNotification is called synchronously inside the push event with no async work in between (or iOS punishes the subscription).
## The 7-Week Build Plan
1
Week 1: Discovery + parent interviews
14 interviews with parents across the 5 clinics. The single biggest friction was forgetting the vaccine card at home. The second was missing the appointment because the WhatsApp reminder buried under 100 forwards. Both shaped the design.
2
Weeks 2–3: PMS shim + booking core
The 11-year-old PMS exposes a SOAP API. We wrapped it in a Next.js API route that translates booking requests to SOAP and back. Cached doctor-availability for 90 seconds with a stale-while-revalidate pattern.
3
Weeks 4–5: PWA shell + service worker
App manifest, icon set (5 sizes for iOS, 3 for Android, plus the maskable variant). Service worker via Workbox. Verified Add-to-Home-Screen on iOS Safari, Chrome Android, Samsung Internet.
4
Week 6: Web push + notification flows
VAPID keys, server-side scheduler that fires push 24 hours, 2 hours, and 30 minutes before each appointment. Tested across iOS 16.4, 17.x, 18.x and Android Chrome.
5
Week 7: Pilot at one clinic + cutover
Soft-launched at the Bandra clinic for 6 days. 412 bookings in pilot. 1 PMS sync bug fixed (date format ambiguity). Cutover all 5 clinics on day 49.
## What Happened in 12 Weeks Post-Launch
Outcome (12 weeks post-launch): 8,140 PWA installs. 62% install-to-booking conversion. 31% drop in no-show rate (24% → 16.7%). Average install-to-repeat-booking 11.4 days. 0 app-store review delays. 1 service-worker bug (a Workbox cache eviction edge case) shipped in week 4 of operation.
## The Pre-Launch Checklist (We Refuse to Cut Over Without This)
- Web push verified on iOS Safari 16.4, 17.x, 18.x and Android Chrome 119+
- Add-to-Home-Screen tested on iOS Safari, Chrome Android, Samsung Internet
- Manifest icons in all required sizes (5 for iOS, 3 for Android, plus maskable)
- Service worker tested on cold network (offline, 2G throttle, intermittent)
- VAPID keys stored in env vars, rotated quarterly
- Push notification 24h/2h/30min schedules tested with sample bookings
- PMS sync delta logged with a 30-day retention and a daily reconciliation report
- Vaccine card tested for offline read after fresh login on a real iPhone in airplane mode
- One-tap reschedule link tested with iOS notification action API
- Roll-back plan: previous service worker version cached for 7-day fallback
## When PWA is the Wrong Choice (We Would Pick Native)
Pick native if: you need continuous Bluetooth (medical device pairing), background audio recording (telemedicine), deep iOS HealthKit/CarPlay integration, on-device camera ML for diagnostic image OCR, or Apple Pay / Google Pay flows that the web payment APIs do not yet handle cleanly. For our pediatric client we genuinely needed none of these. The one feature we deferred — vaccine card scan with on-device OCR — would be a native build for v3.
## Common Mistakes (Each One Hurts)
Symptom: "iOS users do not get push notifications." Cause: forgot the iOS 16.4 requirement that the user must add the PWA to home screen first. Push subscription only works after install. Fix: design the install flow to be the first push-related interaction.
Symptom: "Service worker caches the wrong version after deploy." Cause: forgot to bump the service worker version or used aggressive cache-first on HTML. Fix: NetworkFirst on HTML, version-bump the SW on every deploy, ship a "new version available, refresh" toast.
Symptom: "Android Chrome installs as a Webview, not a PWA." Cause: missing or invalid manifest fields (most often
start_url or
display). Fix: validate the manifest with the Lighthouse PWA audit before shipping.
Symptom: "Push delivery rate is 60% on Android." Cause: Android battery optimisation kills the push service in many OEM ROMs (Xiaomi, Oppo, Realme are the worst). Fix: prompt users on first install to disable battery optimisation for the PWA. Document the per-OEM steps.
Symptom: "Parents say 'where do I download the app?'" Cause: PWA is unfamiliar; parents look in the App Store. Fix: clear in-page banner, WhatsApp install instructions to existing patients, "How to install" video at 90 seconds.
## A Detail That Saved Us On Day 9
On day 9 of operation, push delivery to iPhones dropped from 94% to 71% overnight. We thought we had a VAPID key issue. The actual cause: iOS 18.0.1 had shipped that day with a stricter requirement that the service worker call
showNotification within 5 seconds of receiving the push event. Our handler was doing a database write before the notification call, taking ~6 seconds on a slow network. Fix was a one-line reorder. Recovery to 95% push delivery within 90 minutes. We now bake "showNotification first, side-effects after" into our PWA review checklist. The lesson: read iOS release notes the day they ship, especially the WebKit ones.
## FAQ
### Does iOS Safari really support web push?
Yes, since iOS 16.4 (April 2023) for installed PWAs only. The user must add the site to their home screen first. After that, push works on iOS Safari and Chrome iOS (which runs on WebKit anyway).
### What is the install-acceptance rate for PWA prompts?
In our experience: 18% if you prompt on first visit (low intent), 71% if you prompt after the second successful interaction (high intent + clear value demonstrated). The PWA prompt is one of those features where timing is everything.
### Why no Firebase for push notifications?
VAPID + node web-push library handles both iOS and Android natively. We avoid Firebase to keep the dependency surface small and avoid Google's data-collection defaults for a healthcare client.
### How do you handle the 11-year-old PMS?
A thin Next.js API shim that wraps the PMS's SOAP endpoints. We cache doctor availability for 90 seconds. We write through synchronously for bookings and read authoritative state every 90 seconds. The shim is a single Node service that we can replace independently when the practice upgrades the PMS.
### What about parent identity verification?
OTP-based phone login with optional fingerprint sign-in on the device (Web Authentication API). For sensitive vaccine-card writes we require OTP re-auth with a 15-minute session.
### Can the PWA accept payments?
Yes. We integrated Razorpay for consultation pre-payment. The web checkout works in the PWA exactly as it does on the website. We did not need Apple Pay or Google Pay's app-specific flows.
### What is on the v2 roadmap?
Phase 2 is teleconsultation video (we will use Daily.co's React SDK) and a parent-to-doctor secure messaging thread. Phase 3 is the on-device vaccine-card OCR — we will likely go native at that point or wait for browser camera + ML support to mature.
### What was the team for this build?
Two engineers (one full-stack lead, one frontend specialising in PWA), our designer
Khushi at 0.5 FTE for the parent-facing flows, and our QA lead Manvi at 0.3 FTE for cross-device push testing. Our CTO
Hrishikesh at 0.2 FTE for architecture review.
## Want a Healthcare Booking PWA?
Need a Healthcare Booking PWA?
We build PWAs for 3-15 clinic Indian healthcare practices. Typical engagement: 6-9 weeks, fixed-price ₹3.8L-₹6.2L. We integrate with your existing PMS via REST or SOAP shim. No app-store dependency, no native maintenance burden. First call is with the engineer who would lead your build.
Book a 30-min Call
Related reading: our
9-clinic diagnostics chain booking portal, the
TalkDrill mobile case study, and our
mobile development service.
For more on cross-platform mobile decisions, the team also writes regularly about real-time AI on our edtech product
PenLeap. Email contact@softechinfra.com to receive the PWA-vs-native decision spreadsheet template before the call.