A good share of the "we need an app" requests we receive turn out to be internal tools, such as an order form for sales staff or a check-in screen for field technicians. For many of these, a progressive web app does the job for less money and with fewer moving parts than a store app. For others it falls short, and the gaps only show after launch, usually on an iPhone.
What a PWA Actually Is
A progressive web app, or PWA, is a website built to behave like an installed app. The web app manifest is a small JSON file with the app name, icons, theme colour, and how it should open, for example full screen without the browser bar. The service worker is a script the browser runs alongside your site, which can cache files and data so the app opens even without a connection. It must be served over HTTPS.
Once installed, a PWA gets a home screen icon, opens in its own window, and appears in the app switcher. Underneath it is still your web app, built with whatever your team already uses, such as React, Next.js, Vue, or Laravel. That is often the real reason to choose it.
What PWAs Do Well
There is no store review. You deploy to your own server, and users get the new version the next time they open the app. A wrong price on Friday evening is fixed in minutes, not after Apple approves a build. One codebase serves desktop, Android, and iOS, so your web team does not have to learn Flutter or Kotlin. Public pages can be indexed by Google, which matters for a catalogue or booking site.
Size matters more than people expect in Indonesia. Plenty of mid-range Android phones have 64 or 128 GB of storage filled with WhatsApp media, and people uninstall apps to free space. A PWA usually weighs a few hundred kilobytes to a few megabytes, a typical store app tens of megabytes. For a loyalty programme used twice a month, that decides whether people install at all.
Internal tools and B2B portals are where PWAs fit best: a distributor portal where shops reorder stock, an approval screen for managers, an inspection checklist with photo upload. The users are told to use it, so being findable in a store adds nothing.
The Limits on iOS, Stated Plainly
Most PWA disappointments come from iPhones. Safari supports PWAs, but with a narrower set of features than Chrome on Android.
- Web push notifications work on iOS and iPadOS only from version 16.4, and only for a PWA the user has added to the Home Screen. Someone browsing the site in Safari cannot receive push at all.
- There is no automatic install prompt. Users have to open the Share menu and choose Add to Home Screen, so you need an in-app hint that shows them how.
- Background work is limited. Safari does not support Background Sync, so a form filled in offline is sent when the user opens the app again, not quietly in the background.
- Web Bluetooth, Web NFC, and WebUSB are not available in Safari, so an iPhone PWA cannot talk to a Bluetooth printer, a scanner, or NFC tags.
- A PWA does not appear in App Store search.
Everyday features are fine on both platforms. Photographing a receipt, reading the location for a check-in, and signing in with Face ID or a fingerprint through passkeys all work in a PWA. The gaps open up with continuous background location, connected hardware, or long-running background work.
Android Is the Friendlier Platform
Chrome on Android supports the install prompt, web push without installing, Background Sync, Web Bluetooth, and Web NFC. For an Android-heavy audience, which describes most user bases in Indonesia, a PWA covers more than people assume. One warning: Web Bluetooth only speaks Bluetooth Low Energy, and many cheap thermal receipt printers use classic Bluetooth, so check the printer model first.
You can also publish a PWA to Google Play as a Trusted Web Activity (TWA). Tools such as Bubblewrap or PWABuilder generate a small Android wrapper that opens your PWA full screen in Chrome, and you prove you own the domain with a Digital Asset Links file. You get a Play Store listing with ratings, while features still update from your server. Play policies apply as usual, including yearly target API level updates for the wrapper.
When Native or Flutter Is the Better Call
Pick a store app when the app must do serious work offline. A sales team entering hundreds of orders a day in weak-signal areas needs a real local database and sync with conflict rules. Parts of that work on the web with IndexedDB, but without background sync on iOS it is fragile exactly where it has to hold up.
Also pick native or Flutter when the app leans on hardware or the OS: Bluetooth printers and scanners on iPhones, NFC, continuous background location for drivers, document scanning with edge detection, or heavy camera work. Games belong here too. The last case is trust. A fintech or clinic whose customers ask "is it on the App Store?" gets more credibility from a store listing with reviews than from a home screen icon.
Flutter or two native apps is a separate question we cover in another article. Short version: Flutter for most business apps, native when hardware or new OS features are the product.
Cost and a Side-by-Side Comparison
If you need a web version anyway, a PWA is the cheapest way to also be on phones. In our estimates for internal tools and portals, a PWA usually comes in around 25 to 40 percent below the same scope built as a web admin plus a Flutter app. The backend and admin cost the same either way, so the saving sits in the mobile part. Running costs drop too: no USD 99 a year for Apple, no store releases, one deployment pipeline. The exact figure depends on scope.
| Criteria | PWA | Native or Flutter |
|---|---|---|
| Install | From the browser. Prompt on Android, manual Add to Home Screen on iOS | From Google Play and the App Store |
| Updates | Live on next open, no review | Through store review, users must update |
| Push notifications | Android: yes. iOS: 16.4 or later, only when added to the Home Screen | Full support on both platforms |
| Offline | Cached screens and simple queued forms, no background sync on iOS | Local database, background sync, conflict handling |
| Bluetooth, NFC, background location | Partial on Android, mostly unavailable on iOS | Full access |
| Store presence | Google Play through a TWA, App Store only with a wrapper | Both stores |
| App size | A few hundred KB to a few MB | Usually tens of MB |
| SEO | Public pages can be indexed | Needs a separate website |
| Build cost for the same scope | Often 25 to 40 percent lower | Higher, plus store accounts and release work |
Start as a PWA, Wrap It Later
You do not have to decide forever on day one. Launch a PWA, watch who uses it and on which phones, then wrap it if needed. On Android, a TWA gets you into Google Play within days. For iOS, Capacitor can package the same web code as an App Store app and give it native plugins for push, Bluetooth, or biometrics. Apple rejects apps that are only a website in a frame under its minimum functionality guideline, so the wrapped version needs something app-like, such as push or offline use.
If the people using the app are told to use it, a store listing is worth very little. If they have to choose you over a competitor, it can be worth a lot.
Our honest view: this path works well for internal tools and B2B ordering, less well for consumer apps where the first impression on an iPhone decides adoption. If your launch depends on iPhone users getting push notifications from day one without an install step, start with Flutter and save yourself the rewrite.
How to Build a PWA That Feels Like an App
- 1Get the basics right: HTTPS, a manifest with name, start_url, display set to standalone, and icons including a maskable one, plus a registered service worker. Check them in Chrome DevTools under Application. Lighthouse removed its separate PWA category in 2024, so use DevTools for installability and Lighthouse for performance and accessibility.
- 2Run Lighthouse in mobile mode and aim for good Core Web Vitals. A PWA that loads slowly on the first visit never gets installed.
- 3Choose an offline strategy per type of content. The app shell and static files: cache first. API data such as product lists: network first with a cached fallback, or stale while revalidate. Workbox, or Serwist on Next.js, handles this without writing a service worker by hand.
- 4Design offline forms on purpose. Save submissions locally in IndexedDB, show a clear "waiting to send" state, and retry when the app opens or the connection comes back.
- 5Treat the install prompt as UX. On Android, catch the beforeinstallprompt event and show your own install button after the user has done something useful, not one second into the first visit. On iOS, show a short visual guide.
- 6Ask for push permission only with a clear reason attached, such as "tell me when my order ships", and test it on a real iPhone with the app added to the Home Screen.
- 7Plan for updates. When a new service worker is waiting, show a "new version available" banner with a refresh button.
- 8Test on real devices: a mid-range Android phone on mobile data, and an iPhone on a recent iOS version.
We build PWAs and Flutter apps on the same backend stack, so we have no reason to push one over the other. Tell us what the app must do and who will use it, and we will say which fits. Sometimes the answer is a plain responsive website without the PWA parts.
Key takeaways
- A PWA is a web app with a manifest and a service worker. It installs to the home screen, works offline from a cache, and updates without store review.
- PWAs fit internal tools, B2B portals, and catalogues best, especially for users on low-storage Android phones.
- On iOS, web push needs version 16.4 or later and the app added to the Home Screen. Background sync, Bluetooth, and NFC are not available, and there is no App Store presence without a wrapper.
- Choose native or Flutter for heavy offline sync, connected hardware, background location, games, or when a store listing builds trust.
- Starting with a PWA and wrapping it later with a TWA or Capacitor is a sensible path for B2B products, less so for consumer iPhone audiences.


