When to Build a PWA¶
A Progressive Web App is the right choice when the product is fundamentally a website that benefits from being installable, fast on repeat visits and resilient to bad networks, and when every capability it needs exists in the browsers your users actually run. It is the wrong choice, or only half the answer, when the product depends on background execution, hardware or OS integrations that the web does not expose on your most important platform, which today is usually iOS. This guide turns that sentence into a repeatable decision: a capability checklist mapped to real browser support, a way to evaluate iOS constraints, the skills and maintenance cost a PWA actually requires, hybrid options, a decision flowchart, and worked analyses of six common product types.
Key takeaways
- "Build a PWA" is not a binary choice. It is a ladder from installable website to offline-first app with OS integration, and each rung has its own cost. Decide how far up the ladder to go, not whether to step on it.
- Start from requirements, not technology: list every capability the product needs, map each one to a web API, and check support on the platforms that carry your traffic. One missing must-have on a critical platform changes the answer.
- iOS is usually the deciding platform. Installation is manual, push and badging exist only in Home Screen web apps (iOS 16.4+), there is no background sync of any kind, and every browser uses WebKit.
- The real cost of a PWA is operational: a service worker is a deploy-coupled cache on every user's device, and it needs versioning, update UX, a kill switch and cross-browser testing for as long as it exists.
- Hybrid approaches are normal: a PWA plus a Trusted Web Activity on Google Play, a PWABuilder package for the Microsoft Store, or a native shell only for the platform where the web falls short.
- If you already run a website, adding a manifest and an offline fallback is almost always worth it. The hard decision is whether a PWA can replace a native app, not whether it can complement your site.
The decision you are actually making¶
Most "PWA or not?" debates compare the wrong things. A PWA is not a separate product type that competes with your website. It is your website, progressively enhanced with a Web App Manifest, a service worker and whichever device capabilities the browser offers. That changes the question in three ways:
- If you need a website anyway, the marginal cost of making it a PWA is small at the bottom of the ladder and grows with ambition. The decision is how far to climb.
- If you are choosing between a PWA and a native app, the question is whether the web platform covers your must-have requirements on your must-have platforms. That is a factual question you can answer with a checklist, not a matter of taste.
- If you are choosing between a PWA and both, the question is whether the native app earns its extra codebase through capabilities or distribution the web cannot provide. PWA vs Native vs Hybrid compares the architectures in depth. This guide focuses on the decision procedure.
The PWA capability ladder¶
Thinking in rungs keeps scope honest. Each rung includes the ones below it.
| Rung | What you add | What users get | Initial effort | Ongoing risk |
|---|---|---|---|---|
| 0. Responsive website | HTTPS, responsive layout, good Core Web Vitals | Works everywhere, linkable, indexable | Baseline | Low |
| 1. Installable | Manifest, icons, id, start_url, display | Home screen / dock / taskbar icon, standalone window | Small | Low: static JSON |
| 2. Offline fallback | Service worker that only answers failed navigations with an offline page | A branded offline page instead of the browser's error | Small | Low if the worker stays tiny |
| 3. Fast repeat loads | Precached app shell and static assets, runtime caching for images and fonts | Near-instant repeat visits, resilience on flaky networks | Medium | Medium: cache versioning and update flows |
| 4. Offline reading | Cached content and API responses, IndexedDB for data | Previously seen content works offline | Medium to large | Medium: stale data, storage quotas, eviction |
| 5. Offline writing and sync | Outbox in IndexedDB, conflict resolution, Background Sync where available | Users can create and edit offline | Large | High: data integrity across devices |
| 6. Re-engagement | Web Push, notifications, badging | Messages when the app is closed | Medium | Medium: permission UX, delivery differences |
| 7. OS integration | Share target, file handling, protocol handlers, shortcuts, Window Controls Overlay | Feels like a native app on supporting platforms | Medium per feature | Low to medium: mostly Chromium-only |
Rungs 1 and 2 are cheap and low-risk for almost any site; Migrating an Existing Site walks through them. Rungs 3 to 5 are where engineering time goes and where most PWA bugs live. Rungs 6 and 7 depend heavily on the platform, which is why the capability checklist below matters.
Where PWAs excel¶
These are the situations where a PWA is not a compromise but the best available architecture.
Reach through the URL¶
A PWA is reachable by link from search results, social posts, emails, QR codes and other apps, with no install step between the user and the first screen. Every page is indexable (see SEO for PWAs), and deep links work by default because every screen has a URL. For products whose growth depends on first-time visitors, such as marketplaces, publishers and booking flows, this is decisive. A native app has to win an install before it can deliver any value. A PWA delivers value on the first visit and asks for installation later, once the user has a reason to return. Install Prompts & Custom UI covers how to ask at the right moment.
Continuous delivery without store review¶
Deploying a PWA is deploying a website. The browser checks for a new service worker on navigations into scope (and on functional events such as push when the last check is more than 24 hours old) and your new code reaches users on their next visit, subject to the update pattern you choose. There is no review queue, no minimum OS version to target per release, and no long tail of users stuck on a version from two years ago unless your service worker strategy keeps them there. Updating Service Workers explains the mechanics and the traps.
One codebase across every form factor¶
The same code runs in a browser tab, an installed window on Windows, macOS, ChromeOS and Linux, a WebAPK on Android and a Home Screen web app on iOS. Responsive and adaptive design (see Responsive & Adaptive Design) replaces per-platform UI work. For teams that would otherwise maintain a web app plus Android plus iOS clients, this is the largest cost difference.
Repeat-visit performance and resilience¶
A service worker can serve the app shell and static assets from Cache Storage without touching the network, which removes the network from the critical path for repeat visits. It can also make an unreliable connection behave like a slow but working one. The App Shell Model and Caching Strategies pages show how. On connections that drop in and out ("lie-fi"), a well-built PWA degrades to cached content rather than a blank page.
Low install footprint¶
A WebAPK on Android or a Home Screen web app on iOS is a thin wrapper around a browser engine that is already on the device, so installation adds little storage. Content and assets live in origin storage that the browser manages and can evict under pressure (see Storage Quotas & Persistence). For audiences on entry-level devices with little free storage, this is a real advantage over a native app that ships its own UI runtime.
Desktop apps without a desktop framework¶
On Chromium-based browsers, an installed PWA gets its own window, taskbar or Dock entry, app shortcuts, badges, file and protocol association, and optionally a custom title bar through Window Controls Overlay. Safari 17 and later on macOS Sonoma can add any site to the Dock. For many productivity and internal tools, this replaces an Electron wrapper and its per-app copy of Chromium. Desktop Platforms covers the details per operating system.
Managed deployment for internal tools¶
Chrome and Microsoft Edge let administrators force-install web apps through the WebAppInstallForceList enterprise policy, and ChromeOS admins can pin them to the shelf. An internal tool built as a PWA can therefore be deployed to a fleet without an MDM app-packaging pipeline, and updated by deploying the website.
Where PWAs struggle¶
The web platform has closed most of the gap for foreground apps. The remaining gaps cluster in five areas. If your product lives in one of them, plan for it explicitly.
Background execution¶
A service worker runs only in response to events and is terminated when idle: Chromium stops it after about 30 seconds without pending events and caps each event at five minutes in general (three minutes for sync, and a shorter custom timeout for push). There is no general-purpose background execution on the web. What exists:
| Background need | Web mechanism | Where it works |
|---|---|---|
| Retry a failed request when connectivity returns | Background Sync | Chromium only |
| Refresh content on a schedule | Periodic Background Sync | Chromium only, installed apps, browser-controlled interval |
| Download large files with the app closed | Background Fetch | Chromium only; a November 2025 intent to deprecate it for low usage did not reach consensus, so it remains shipped but should be treated as fragile |
| Wake the app for a server event | Push | All engines; iOS only for Home Screen web apps, and every push must show a notification |
| Background location, geofencing, BLE scanning with the app closed | None | Not available on the web |
| Long audio or VoIP sessions with the app backgrounded | Media playback continues in some cases; no VoIP integration | Test per platform |
If your product needs to do work while the user is not looking at it (track a run, sync a large dataset overnight, receive a call), the web alone will not cover it on iOS and only partly on Android.
iOS distribution and discovery¶
Safari never shows an install prompt, fires no beforeinstallprompt event, and has no API to trigger installation. Users install through the Share sheet. Since iOS 26, any site added to the Home Screen opens as a web app by default, which removes technical barriers but not the discovery problem: most iOS users do not know the flow exists. If the product needs a large installed base on iPhone (for push-driven engagement, for example), budget for in-app education or a native shell. The next section goes deeper.
Hardware and OS integrations¶
Web Bluetooth, WebUSB, WebHID and Web NFC are Chromium-only, Web NFC is Android-only, and Web Serial exists outside Chromium only in desktop Firefox 151 and later, gated behind a site-permission add-on. Contacts are available only through the Contact Picker on Chrome for Android (Safari on iOS has it only behind an experimental feature flag). There are no web APIs for health data, calendars, home screen widgets, keyboard extensions, CallKit-style call UI, or background geolocation. Hardware & Device APIs documents what exists and where.
App store expectations¶
If stakeholders require a presence in the Apple App Store, a PWA alone does not provide it. Google Play accepts PWAs packaged as Trusted Web Activities, and the Microsoft Store accepts PWAs directly (see Publishing to App Stores). Apple requires a native wrapper, and App Review guideline 4.2 ("Minimum Functionality") rejects apps that are little more than a repackaged website.
Heavy real-time graphics and large asset budgets¶
WebAssembly and WebGPU make serious graphics possible in the browser. WebGPU shipped in Chrome 113 on ChromeOS, macOS and Windows (Linux followed in Chrome 144), Chrome 121 on Android, Safari 26 and, on Windows only, Firefox 141. The constraints are elsewhere: memory limits in mobile browsers are lower and less predictable than for native apps, large asset bundles compete for origin storage, and fullscreen is limited on iPhone. High-end 3D games still favor native engines. Casual and mid-weight games are a good fit.
Requirements checklist mapped to capabilities¶
Write down every capability the product needs and classify it as must-have (the product fails without it), should-have (degraded experience without it) or nice-to-have. Then map each to the table below and look only at the columns for the platforms that carry your traffic. The rule is simple: a must-have that shows ❌ on a must-have platform requires a hybrid or native answer for that platform.
Support data as of September 2026. Check MDN and caniuse.com for live data, and Platform Support for the full matrix with version numbers.
| Requirement | Web capability | Chromium desktop | Chrome Android | Safari iOS / iPadOS | Firefox | Where to read more |
|---|---|---|---|---|---|---|
| Icon on home screen / dock / taskbar | Manifest + install | ✅ | ✅ WebAPK | ⚠️ manual via Share sheet | ⚠️ Windows taskbar; Android shortcut | Installability |
| Custom install button | beforeinstallprompt | ✅ | ✅ | ❌ | ❌ | Install prompts |
| Offline reading of seen content | Service worker + Cache API / IndexedDB | ✅ | ✅ | ✅ | ✅ | Caching |
| Offline edits synced later | IndexedDB outbox + sync on open | ✅ | ✅ | ✅ | ✅ | Offline-first |
| Sync with the app closed | Background Sync | ✅ | ✅ | ❌ | ❌ | Background Sync |
| Scheduled refresh | Periodic Background Sync | ✅ installed | ✅ installed | ❌ | ❌ | Periodic Sync |
| Push notifications | Push API + Notifications | ✅ | ✅ | ⚠️ Home Screen only, 16.4+ | ✅ | iOS Web Push |
| Icon badge count | Badging API | ⚠️ not Linux | ❌ (notification dot instead) | ⚠️ Home Screen only, 16.4+ | ❌ | Badging |
| Share content out | Web Share | ✅ Chrome 128+ (earlier: Windows and ChromeOS only) | ✅ | ✅ | ⚠️ Android only | Web Share |
| Receive shares from other apps | Web Share Target | ⚠️ ChromeOS only | ✅ | ❌ | ❌ | Share Target |
| Open and save user files | File System Access pickers | ✅ | ✅ | ❌ (use <input type=file> and downloads) | ❌ | File System Access |
| Be the default app for a file type | File Handling | ✅ | ❌ | ❌ | ❌ | File Handling |
| Large private on-device files | Origin Private File System | ✅ | ✅ | ✅ | ✅ | OPFS |
| Camera and microphone | getUserMedia(), <input capture> | ✅ | ✅ | ✅ | ✅ | Media & System APIs |
| Foreground location | Geolocation | ✅ | ✅ | ✅ | ✅ | Device APIs |
| Background location / geofencing | None | ❌ | ❌ | ❌ | ❌ | Native required |
| Bluetooth LE peripherals | Web Bluetooth | ✅ | ✅ | ❌ | ❌ | Device APIs |
| USB, HID or serial devices | WebUSB / WebHID / Web Serial | ✅ | ⚠️ WebUSB; Web Serial since 148 (Bluetooth RFCOMM only in 138–147); no WebHID | ❌ | ⚠️ Web Serial only, desktop 151+, add-on gated | Device APIs |
| NFC tags | Web NFC | ❌ | ✅ | ❌ | ❌ | Device APIs |
| Pick contacts | Contact Picker | ❌ | ✅ | 🧪 | ❌ | Device APIs |
| Keep the screen on | Screen Wake Lock | ✅ | ✅ | ✅ (Home Screen apps since 18.4) | ✅ | Media & System APIs |
| Sign-in without passwords | WebAuthn / passkeys | ✅ | ✅ | ✅ | ✅ | Authentication |
| Checkout | Payment Request, Apple Pay, Google Pay | ✅ | ✅ | ✅ Apple Pay | 🧪 | Payments |
| GPU compute and modern 3D | WebGPU | ✅ 113+ (Linux 144+) | ✅ 121+ | ✅ 26+ | ⚠️ Windows 141+ | Media & System APIs |
| Custom title bar | Window Controls Overlay | ✅ | – | – | ❌ | WCO |
Handle web+app: links | Protocol handlers | ✅ | ❌ | ❌ | ⚠️ API only | Protocol handlers |
⚠️ entries are usable with the constraint named in the cell. 🧪 means behind a flag or experimental setting.
Measure your own audience before you decide¶
Global support tables tell you what browsers can do. Your analytics tell you which browsers your users run. Before committing, ship a small capability probe to your existing site and record which features are available to your actual traffic. The excerpt below shows the shape: presence checks only (never a permission prompt), one beacon per session. Take the full list of detection expressions from Capabilities and add the ones your product depends on.
function detectCapabilities() {
const hasSW = "serviceWorker" in navigator;
return {
serviceWorker: hasSW,
// navigator.standalone first: iOS web apps with display "standalone" match
// (display-mode: fullscreen), and macOS Safari Dock apps also set it.
standalone:
navigator.standalone === true ||
["standalone", "fullscreen", "minimal-ui", "window-controls-overlay"].some(
(mode) => matchMedia(`(display-mode: ${mode})`).matches,
),
installPromptEvent: "onbeforeinstallprompt" in window, // Chromium only
push: hasSW && "PushManager" in self,
backgroundSync: hasSW && "SyncManager" in self,
fileSystemAccess: "showOpenFilePicker" in self,
webSerial: "serial" in navigator,
// ...add the capabilities your product depends on.
};
}
async function reportCapabilities(endpoint) {
try {
if (sessionStorage.getItem("cap-probe-sent")) return; // once per session
const body = JSON.stringify({ caps: detectCapabilities(), ts: Date.now() });
// sendBeacon survives page unload; fall back to a keepalive fetch.
if (!navigator.sendBeacon?.(endpoint, body)) {
await fetch(endpoint, { method: "POST", body, keepalive: true });
}
sessionStorage.setItem("cap-probe-sent", "1");
} catch (err) {
console.debug("capability probe skipped", err); // storage can throw in private modes
}
}
reportCapabilities("/analytics/capabilities");
Three caveats when reading the results:
- Presence is not function. Android WebView exposes
navigator.usbbut doesn't implement WebUSB, so an in-app browser reports a capability it can't use. Likewise,navigator.setAppBadge()resolving doesn't mean a badge appeared: Chromium on Linux has no OS-level badge to draw.Notificationis undefined in iOS Safari tabs but defined in Home Screen web apps, so the same iPhone reports differently depending on how the user opened your site. - Segment by display mode. Record
standalonealongside every other flag so you can see how many iOS users could receive push today (those already in a Home Screen web app) versus in principle. - Weight by value, not by sessions. A feature available to 95% of sessions but missing for the 5% who generate most revenue can still be a must-have. Join the probe data with your business metrics. Analytics for PWAs covers instrumentation in more depth.
Evaluating iOS constraints¶
For most consumer products, iOS carries a large share of traffic and an even larger share of revenue, and it is the platform where the web has the most rules. Evaluate it separately and explicitly.
What iOS gives a PWA today¶
- Service workers, Cache Storage, IndexedDB and OPFS work in Safari and in Home Screen web apps, so offline reading and offline editing with sync-on-open are fully possible.
- Installation through Share → Add to Home Screen. Since iOS and iPadOS 26, WebKit states that "by default, every website added to the Home Screen opens as a web app," and that there are "zero requirements for 'installability' in Safari." Other browsers on iOS can also add Home Screen web apps since iOS 16.4.
- Web Push and notifications since iOS 16.4, only for Home Screen web apps, delivered through Apple's push service with standard VAPID. Declarative Web Push arrived in iOS 18.4.
- Badging for Home Screen web apps since iOS 16.4.
- WebAuthn passkeys (Safari 13), Apple Pay through Payment Request (Safari 11.3), Web Share (iOS Safari 12.2), camera and microphone are long-standing; WebGPU arrived in Safari 26.
- Storage exemption: Home Screen web apps are exempt from Safari's rule that deletes script-writable storage after seven days of Safari use without interaction with the site.
What iOS does not give a PWA¶
- No install prompt or
beforeinstallpromptevent, and noappinstalledevent. - No Background Sync, Periodic Background Sync or Background Fetch. Work happens when the app is open or in a push handler.
- No push in Safari tabs. Users must install first, and the permission request must follow a user gesture inside the installed app.
- Silent push is not allowed. Each push must display a notification; WebKit penalizes subscriptions that don't.
- No Web Bluetooth, WebUSB, WebHID, Web Serial or Web NFC, no File System Access pickers, no share target, no file handling, no protocol handlers.
- No alternative engine for Home Screen web apps. The EU (iOS 17.4) and Japan (iOS 26.2) allow alternative browser engines in browser apps, but Home Screen web apps remain on WebKit, and as of September 2026 no alternative-engine browser has shipped on iOS. Plan for WebKit everywhere on iOS.
- Separate storage from Safari. A Home Screen web app has its own storage. Since iOS 17.2, Safari's cookies are copied into the web app when it is created, so users generally stay signed in, but
localStorage, IndexedDB and caches are not copied (behavior when the app is created from another iOS browser isn't documented). Design the first launch accordingly.
iOS & iPadOS and Web Push on iOS & Safari document each of these in detail.
An iOS evaluation worksheet¶
Answer each question for your product. Every "yes" in the right-hand column is a reason to consider a native or hybrid iOS client.
| Question | If the answer is yes |
|---|---|
| Does the product need push notifications to deliver its core value (messaging, alerts, delivery status)? | Push works only after the user installs. Estimate what share of iOS users will realistically install. If that share is too small, a native iOS client or companion app is justified. |
| Does anything need to run while the app is closed, other than showing a pushed notification? | Not possible on iOS web. Native required for that feature. |
| Does the product need Bluetooth, NFC, USB or other peripherals on iPhone or iPad? | Not possible on iOS web. Native required. |
| Must the app be listed in the App Store (procurement rules, partner requirements, brand)? | Needs a native wrapper with genuine native functionality to pass guideline 4.2. |
| Does the product sell digital goods consumed in the app? | Store policies decide the payment flow for store-distributed builds. Web checkout in the PWA is unaffected by store rules. |
| Do users need to receive shares from Photos or other apps? | No share target on iOS. Native share extension required, or accept an upload flow. |
| Must large offline datasets survive for weeks without the user opening the app? | Home Screen web apps are exempt from the seven-day rule, but storage can still be evicted under pressure. Request persistence and design for re-sync. See Storage Quotas. |
| Is the first-run experience in Safari good enough that users will return to install? | If not, fix that first: install rates depend on it more than on any API. |
Decide on the iOS gap, not on iOS as a whole
A common outcome of this worksheet is "PWA everywhere, plus a thin native iOS app for one missing capability" (for example, a Capacitor build that adds native push and a share extension). That is far cheaper than two full native clients, and the web build keeps serving every other platform. See Hybrid approaches below.
Team skills and organizational fit¶
A PWA uses the web stack your team already knows, but the service worker introduces a class of problems most web teams have not dealt with: code and cached data that persist on user devices across deploys. Check that the team has, or can build, these skills.
| Skill | Why a PWA needs it | Signs you have it | How to build it |
|---|---|---|---|
| HTTP caching and CDNs | Service worker caching interacts with HTTP caching and CDN rules. Mistakes produce stale apps that survive deploys. | The team can explain Cache-Control, ETag and Vary behavior for each asset type today. | HTTP Caching & Service Workers |
| Service worker lifecycle | Install, waiting, activation and update behavior decide when users get fixes. | Someone can predict what happens to an open tab when a new version deploys. | Lifecycle, Updating |
| Client-side data modeling | Offline reading and writing need IndexedDB schemas, migrations and sync. | The team has shipped schema migrations for client storage before. | IndexedDB, Offline-first |
| Cross-browser testing | Behavior differs across Chromium, WebKit and Gecko, and across tab and installed contexts. | CI runs in more than one engine; someone owns a real iPhone for testing. | Automated Testing, DevTools |
| Web security | Service workers can serve any response for their scope; CSP, scope and cache poisoning matter. | Security reviews already cover client-side code. | Service Worker Security |
| Performance engineering | A careless service worker slows down navigations. | The team monitors field Core Web Vitals. | Measuring Performance |
Two organizational questions matter as much as skills:
- Who owns the service worker? It touches every request on the origin. In a company where several teams deploy to one origin, a single team must own
sw.js, its routes and its release process, or teams will break each other's caching. Consider narrower scopes or separate origins for independent apps (see Registration & Scope). - Is the release process ready for a persistent client? A website deploy that breaks something is fixed by the next deploy. A service worker deploy that breaks navigation can keep serving the broken version until users pick up a fix. You need a pre-built kill switch, and your deploy pipeline must keep old hashed assets available while old clients still request them.
Technical cost and ongoing maintenance¶
The initial build of a PWA is rarely the expensive part. The recurring cost comes from running a cache and a background script on millions of devices you cannot inspect. Budget for each item below.
| Cost item | Initial | Recurring | What goes wrong without it |
|---|---|---|---|
| Manifest and icons | Small | Update when branding changes; test the install UI per platform | Blurry or cropped icons, wrong name, broken app identity after a start_url change (see App Identity & Updates) |
| Service worker and caching strategy | Medium | Review routes on every feature that adds endpoints or asset types | Stale content, cached personalized pages, broken API calls |
| Build integration (precache manifest, revisioning) | Small with Workbox or Vite PWA | Keep tooling current | Precache lists that drift from the build output; version mismatches |
| Update UX | Medium | Test every release that changes the shell or message formats | Users stuck on old versions, reload loops, chunk-load errors |
| Kill switch and rollback | Small | Test it periodically | An incident with no way to stop the broken worker |
| Offline data and sync | Large | Schema migrations, conflict handling, support tickets about lost edits | Data loss, duplicate submissions |
| Push infrastructure | Medium | Subscription hygiene, expired endpoints, per-platform delivery rules | Silent failures, penalties on iOS for missing notifications |
| Cross-browser testing matrix | Medium | Every release, and every major browser release | Regressions discovered by users |
| Storage monitoring | Small | Watch quota errors and eviction in the field | Offline mode silently disappears |
| Platform change tracking | None | Follow browser release notes | Surprises like the ones below |
The platform changes under you more than native platforms do, and the changes are delivered to users without your involvement. Recent examples that affected PWA teams:
- Chrome removed the requirement for a service worker
fetchhandler from menu installation in Chrome 108 on Android and Chrome 112 on desktop, and shows its own default offline page for installed apps that don't provide one (Chrome for Developers). - Lighthouse 12.0 (April 2024) removed the PWA category, citing Chrome's updated installability criteria, so teams that used the PWA score as a release gate had to replace it (release notes). Lighthouse & Auditing covers what to use instead.
- iOS 26 made every site added to the Home Screen open as a web app by default, so sites that never planned for standalone mode started running in it (WebKit).
- Firefox 143 (September 2025) added taskbar web apps on Windows (release notes).
None of these required emergency work from well-built PWAs, but each changed an assumption. Assign someone to read browser release notes each month.
Comparing maintenance with native clients¶
A fair comparison counts all clients. A web app plus two native apps means three codebases, three release trains, store review for two of them, and a long tail of old native versions that your API must keep supporting. A PWA removes the store trains and most of the version long tail, but adds the service worker operations listed above. For a product that needs a website anyway, the PWA is almost always cheaper to maintain than web plus native. For a product that doesn't need a website at all (a hardware companion app, for example), the comparison is less favorable, because the web codebase exists only to become the app.
Hybrid approaches¶
Many successful products combine a PWA with native packaging where it pays off. These are the common patterns, from lightest to heaviest.
| Approach | What it is | Platforms | Keeps web codebase? | Gains | Costs |
|---|---|---|---|---|---|
| PWA only | Website + manifest + service worker | All | Yes | Lowest cost, instant updates | No App Store listing, iOS limits |
| PWA + Trusted Web Activity | Your PWA in a Play Store package that runs full-screen in Chrome | Android | Yes, same origin | Play Store listing, Play Billing through the Digital Goods API | Digital Asset Links setup, Play policies, a thin Android project to maintain |
| PWA + Microsoft Store package | PWA packaged (for example with PWABuilder) for the Microsoft Store | Windows | Yes | Store listing on Windows | Store listing upkeep |
| PWA + native shell on iOS | Same web build inside a WebView app (for example Capacitor) with native plugins | iOS (optionally Android) | Mostly | App Store listing, native push, widgets, share extension | A native project, App Review, guideline 4.2 |
| PWA + native companion | Full native app for one job (hardware, background tracking), PWA for everything else | Any | Yes | Best of both for split use cases | Two codebases, feature overlap to manage |
| Native first, web as funnel | Native apps are the product; the website is a lightweight PWA for acquisition and sharing | Any | Partly | Native depth, web reach for first visit | Full native cost |
A few details matter when you mix packaging and the web:
- A Trusted Web Activity renders your live origin, so your service worker, storage and updates are the same as in Chrome. When Chrome launches a TWA,
document.referrerfor the first navigation starts withandroid-app://followed by the package name, which lets you tag analytics or adjust UI (for example, hide a web install button). The snippet below shows the pattern. - A WebView-based iOS shell does not share storage or service worker registrations with Safari or with a Home Screen web app. If the shell loads your live site rather than bundled assets, App Review is more likely to treat it as a repackaged website. Publishing to App Stores covers the trade-offs.
- Choose one canonical install path per platform. Offering "Install the web app" and "Get it on Google Play" side by side confuses users and splits your push subscriptions across two installs. Detecting Installed Apps shows how to check for the related native app with
getInstalledRelatedApps()on Chromium.
// Classifies how the current session was launched so analytics and UI can
// adapt. Call once at startup, before any client-side navigation changes
// document.referrer.
export function getLaunchContext() {
// Trusted Web Activity: Chrome sets the referrer of the launch navigation
// to android-app://<package-name>/
if (document.referrer.startsWith("android-app://")) {
return { context: "twa", package: document.referrer.slice(14).replace(/\/$/, "") };
}
// Check Safari's legacy flag first: iOS web apps with display "standalone"
// match (display-mode: fullscreen), and macOS Dock web apps also set it.
if (navigator.standalone === true) {
return { context: "installed", displayMode: "standalone" };
}
const modes = ["window-controls-overlay", "fullscreen", "standalone", "minimal-ui"];
const mode = modes.find((m) => matchMedia(`(display-mode: ${m})`).matches);
if (mode) return { context: "installed", displayMode: mode };
return { context: "browser", displayMode: "browser" };
}
// Persist the first classification for the session: after a client-side
// navigation document.referrer no longer reflects the launch.
export function launchContextForSession() {
try {
const saved = sessionStorage.getItem("launch-context");
if (saved) return JSON.parse(saved);
const ctx = getLaunchContext();
sessionStorage.setItem("launch-context", JSON.stringify(ctx));
return ctx;
} catch {
return getLaunchContext(); // sessionStorage unavailable (privacy modes)
}
}
The decision flowchart¶
The flowchart condenses the checklist, the iOS worksheet and the hybrid options into one path. Start at the top with your list of must-have requirements and your platform traffic split.
flowchart TD
A["List must-have requirements and platform traffic"] --> B{"Do you need a website anyway?"}
B -- yes --> C["Make it installable and add an offline fallback (rungs 1-2)"]
B -- no --> D{"Is the product mostly foreground UI over network data?"}
D -- no --> N["Native or cross-platform native; consider a web funnel"]
D -- yes --> C
C --> E{"Every must-have available on every must-have platform?"}
E -- yes --> F["PWA only: climb the ladder as far as users need"]
E -- no --> G{"Are the gaps only on iOS?"}
G -- yes --> H{"Is the gap push reach, background work or hardware?"}
H -- "push reach only" --> I["PWA plus install education; measure install rate, revisit later"]
H -- "background work or hardware" --> J["PWA plus a native or Capacitor iOS client for the gap"]
G -- no --> K{"Are the gaps limited to one feature area?"}
K -- yes --> L["PWA plus a native companion app for that feature"]
K -- no --> N
F --> M{"Store listing required?"}
I --> M
M -- "Google Play" --> O["Add a Trusted Web Activity"]
M -- "Microsoft Store" --> P["Package with PWABuilder"]
M -- "Apple App Store" --> J
M -- no --> Q["Ship the PWA; review the checklist every six months"] Two notes on reading it. First, the "review every six months" step is real work: gaps close (Safari added Home Screen Web Push and badging in 2023, WebGPU in 2025 and the Static Routing API in 2026), and a decision to go native for one capability should be revisited when that capability ships. Second, the flowchart ignores preferences such as "native feels better." If that argument comes up, turn it into testable requirements (startup time, scroll performance, specific gestures) and measure them; Runtime Performance and App-Like UX Patterns show what the web can do.
Scenario analyses¶
The same procedure applied to six common product types. Each analysis lists the typical must-haves, where the web stands, a recommended architecture and the main risks. Your product will differ; use these as templates, not verdicts.
E-commerce and marketplaces¶
Typical must-haves: fast first visit from search and social, product pages indexable, cart and checkout, account and order history, order-status notifications, optionally saved items offline.
Where the web stands: everything above is available across engines. Payment Request with Apple Pay or Google Pay and passkeys work in all major browsers (Payments, Authentication). Order-status push works everywhere except iOS Safari tabs.
Recommendation: PWA. Server-render or statically generate product and category pages for SEO and first-visit speed, then add a service worker that precaches the shell and static assets and uses stale-while-revalidate for product images. Do not cache cart, checkout or account pages in shared caches: they are personalized and the cost of serving stale prices or someone else's cart is high. Treat offline as "browse what you've seen, queue wishlist changes," not "check out offline."
Risks: stale prices and stock from over-eager caching (use short-lived runtime caches and always revalidate prices at checkout); push reach on iOS limited to installed users (use email or SMS for critical order updates); cache and CDN rules interacting badly with personalization (see Migrating an Existing Site for a safe approach).
Media, news and streaming¶
Typical must-haves: fast article loads, breaking-news alerts, offline reading of saved articles, audio or video playback, possibly DRM, possibly downloads for offline viewing.
Where the web stands: article caching and offline reading are straightforward, and Streaming Responses let you assemble pages from cached header and footer plus fresh content. Media Session integrates playback with lock screens and hardware keys (Media & System APIs). Encrypted Media Extensions provide DRM (FairPlay in Safari, Widevine in Chromium and Firefox). Large offline downloads are the weak point: Background Fetch is Chromium-only, with usage low enough that Chromium engineers proposed deprecating it in November 2025, so on iOS downloads happen only while the app is open, and large media competes for storage.
Recommendation: PWA for news and publishing, including saved-article offline reading, with push for breaking news. For streaming services where offline downloads of long videos are a core feature on iPhone, add a native client for downloads or accept an online-only iOS experience.
Risks: storage quota and eviction for media caches (store media in OPFS or Cache Storage with explicit size budgets and request persistence); push fatigue and iOS's visible-notification rule; range requests for cached media need special handling in the service worker (Advanced Techniques).
Internal tools and line-of-business apps¶
Typical must-haves: SSO, desktop-first data entry, fast startup, printing or exports, sometimes barcode scanning, sometimes peripherals (label printers, scales, scanners).
Where the web stands: excellent on managed Chromium desktops: installation can be forced by policy, File System Access and File Handling support document workflows, WebUSB, WebHID and Web Serial cover many peripherals, and updates are just deploys. On iPads and iPhones used in the field, peripheral APIs are missing.
Recommendation: PWA, especially when the fleet is Chromium on Windows or ChromeOS. Use Window Controls Overlay and app shortcuts to make it feel native. If the fleet includes iOS devices that must talk to peripherals, check whether the peripheral offers a network or HID keyboard mode (many scanners do), which works without any special API.
Risks: the tool depends on Chromium-only APIs, which is acceptable in a managed fleet but should be a conscious decision; long-lived sessions need update checks (see periodic registration.update() in Updating Service Workers); SSO redirects out of scope may open in a browser tab rather than the app window on some platforms (Protocol Handlers & Launch Handling).
Games¶
Typical must-haves: smooth rendering, audio, input (touch, keyboard, gamepad), fullscreen, asset downloads, save data, sometimes leaderboards and in-app purchases.
Where the web stands: Canvas, WebGL and WebGPU (all three engines, with Firefox on Windows), WebAssembly, Web Audio and the Gamepad API cover the core. The Fullscreen API works on iPad but not iPhone; an installed standalone web app is the practical substitute there. Assets can be precached or stored in OPFS, but large downloads count against origin quota and can be evicted. In-app purchases of digital goods are subject to store rules only when distributed through a store.
Recommendation: PWA for casual, puzzle, card, word and social games, where instant play from a link is the growth engine. For high-end 3D games with multi-gigabyte assets, a native engine and store distribution remain the stronger choice; a web build can still serve as a demo or companion.
Risks: audio restrictions until the first user gesture; memory limits on mobile Safari; save data lost to eviction (sync saves to a server and request persistence); asset updates must be versioned to avoid mixing old and new files across a service worker update.
Productivity and creative tools¶
Typical must-haves: open and save local files, work offline on documents, keyboard shortcuts, multiple windows, clipboard, large client-side computation, collaboration.
Where the web stands: strong on Chromium desktop: file pickers with write access, file handling, launch handling, WCO, and OPFS with synchronous access handles in workers for fast storage (Origin Private File System). On Safari and Firefox, OPFS works but user-visible file access falls back to <input type="file"> and downloads. WebAssembly brings existing C, C++ and Rust engines to the browser.
Recommendation: PWA, designed around progressive enhancement of file access: native-like save on Chromium, "download a copy" elsewhere. Keep documents in OPFS or IndexedDB with server sync so the user never depends on a local file path. Use offline-first data and sync for collaboration.
Risks: users expect Ctrl+S to save in place, which only Chromium supports; data integrity across tabs and devices (use Web Locks or BroadcastChannel for single-writer coordination); memory use for large documents.
Offline field apps¶
Typical must-haves: complete forms, inspections or deliveries with no connectivity for hours or days; photos; foreground GPS; sync when back online; reliability over months of daily use; often a managed device fleet.
Where the web stands: the data layer is fully possible: IndexedDB for records, OPFS or IndexedDB for photos, an outbox with idempotency keys, sync on app open and on online events everywhere, plus Background Sync on Chromium. Camera and foreground geolocation work everywhere. What's missing: background sync on iOS and Firefox, background location, and guaranteed storage (persistence is granted by heuristics, and evictions still happen on devices that run out of space).
Recommendation: PWA when the fleet is Android or Chromium-based and managed, which lets you control browser versions and install the app by policy. On iOS fleets, a PWA works if the workflow tolerates "sync happens when the app is open," which it usually does if the UI shows unsynced counts clearly. Choose native if data must upload while the device sits in a pocket, or if the app must track location in the background.
Risks: silent data loss is the failure that ends projects. Call navigator.storage.persist(), show unsynced items prominently, never delete local records until the server confirms them, and export a diagnostic bundle for support. Offline UX & Fallbacks and Offline-First Data & Sync cover the patterns.
Scenario summary¶
| Scenario | Default recommendation | Deciding factor | Typical hybrid addition |
|---|---|---|---|
| E-commerce | PWA | First-visit speed and SEO | TWA for a Play listing |
| News and publishing | PWA | Link-driven traffic | None needed |
| Video streaming with downloads | Hybrid | Offline downloads on iOS | Native iOS client |
| Internal tools (Chromium fleet) | PWA | Managed deployment, peripheral APIs | None needed |
| Casual games | PWA | Instant play from a link | TWA or store packages for discovery |
| High-end 3D games | Native | Asset size, GPU and memory headroom | Web demo |
| Productivity tools | PWA | Cross-platform reach, file handling on Chromium | None, or desktop store packages |
| Offline field apps | PWA on Android and Chromium; evaluate iOS | Background sync and location needs | Native iOS client if background work is required |
Common pitfalls in the decision¶
- Deciding on global support data instead of your traffic. A feature missing in a browser your users don't run doesn't matter. A feature missing on the platform that brings most of your revenue does. Run the capability probe first.
- Treating "installable" as the goal. Installation is a user choice that follows value. A PWA that is fast and reliable in a tab delivers most of the benefit even if few users install it.
- Assuming push reach on iOS equals push reach on Android. On iOS it is limited to users who installed the app. Model your notification strategy on realistic install rates.
- Underestimating the service worker's blast radius. One bad route can break every page on the origin for every returning user. Start small (an offline fallback only), add caching route by route, and keep a kill switch ready. Pitfalls & Anti-Patterns lists the classic mistakes.
- Choosing native to avoid a capability gap that has a UX workaround. No share target on iOS? An upload button may be enough. No File System Access in Safari? "Download a copy" may be enough. Check with users before paying for a second codebase.
- Choosing a PWA to avoid store policies you will need anyway. If the business requires an App Store listing, plan the native shell from the start rather than discovering guideline 4.2 at submission time.
- Never revisiting the decision. Support changes every browser release. Put the checklist on a six-month review cycle.
Further reading¶
On this site
- PWA vs Native vs Hybrid: architecture, performance and store comparison in depth
- Platform Support: the full feature matrix with version numbers
- iOS & iPadOS: every iOS rule that affects PWAs
- Migrating an Existing Site: the low-risk path to rungs 1 through 3
- Publishing to App Stores: the hybrid and store distribution options
- Offline-First Data & Sync: what rung 5 really involves
- Case Studies: how real products made this decision
- The future: native, PWA or both?
External references
- WebKit: WebKit Features in Safari 26.0 (Home Screen web app changes)
- Chrome for Developers: Revisiting Chrome's installability criteria
- web.dev: Learn PWA
- MDN: Progressive web apps
- Apple: App Review Guidelines
- Chrome Enterprise: WebAppInstallForceList policy
- caniuse.com for live browser support data