Back to Blog
PWAWeb PerformanceMobileWeb Fundamentals

Your Website Can Be an App

Code437 min read
THREE PILLARS OF A PROGRESSIVE WEB APPYOUR PWAInstalled · Offline-readyWEB MANIFESTmanifest.jsonApp name & iconsTheme & splash screenStandalone display modeStart URLEnables InstallSERVICEWORKERRuns in the backgroundIntercepts network requestsCaches assets & pagesPush notificationsEnables OfflineHTTPSTLS / Secure originRequired by browsersEncrypts all trafficEnables service workersTrusted origin for APIsEnables TrustAll three are required — remove any one and the browser will not offer the install prompt
The three pillars of a Progressive Web App: a web manifest, a service worker, and HTTPS, working together to deliver an app-like experience from a browser tab.

A Website That Installs Like an App

If you visit certain websites on a mobile browser, you will see a prompt asking if you want to add the site to your home screen. Tap it, and an icon appears alongside your native apps. Open it and there is no browser chrome, no address bar, just the site filling the screen like any other app. It loads fast. It works without a connection. It can send push notifications.

That is a Progressive Web App. It is not a separate codebase or a special framework. It is a regular website that meets a specific set of technical criteria, which causes browsers to treat it differently and unlock capabilities that ordinary sites do not have.

What Makes Something a PWA

Browsers use three requirements to decide whether a site qualifies as a Progressive Web App. All three must be present. Each one does a distinct job.

A web manifest is a JSON file that tells the browser how to present the app when it is installed. A service worker is a JavaScript file that runs in the background, separate from the page, and controls how the app handles network requests. HTTPS is required for both: browsers will not activate a service worker on an insecure origin.

Remove any one of these and the browser will not offer an install prompt, and background features like offline support and push notifications will not function.

The Web Manifest

The manifest is a file called manifest.json, linked from your HTML. Its purpose is metadata: how the app should look and behave once it is installed. A minimal manifest includes the app name, a set of icons at various sizes, the URL to open on launch, and a display mode.

The display mode is what determines the visual experience. Setting it to standalone removes the browser chrome entirely. The user sees only your UI, framed by the operating system's window, exactly like a native app. minimal-ui keeps a small navigation bar. browser changes nothing and is mainly useful for testing.

The manifest also controls the theme color, which tints the OS status bar on Android, and the background color shown during the splash screen while the app loads. Getting these right matters: a white flash on a dark-themed app is noticeable and avoidable.

The Service Worker

The service worker is the most powerful part of the PWA stack and the least intuitive. It is a JavaScript file that the browser installs separately from the page. Once registered, it runs in the background even when the user has closed the tab, and it intercepts every network request the page makes.

That interception is where the useful behavior comes from. The service worker sits between your app and the network and can decide, for each request, whether to fetch from the network, serve from a local cache, or do both and return whichever responds first.

Caching strategies

The most common pattern is cache-first for static assets. On install, the service worker pre-caches your JavaScript, CSS, fonts, and key images. Subsequent requests for those files are served directly from the device, without touching the network. Page loads feel immediate because the assets are already there.

For dynamic content, network-first is more appropriate. The service worker tries the network, and falls back to a cached version if the request fails. This gives users stale but useful content when they are offline, rather than an error screen.

Stale-while-revalidate is a third option: serve the cache immediately, then fetch a fresh copy in the background and update the cache for next time. It gives instant response without permanently serving outdated content.

Offline support

True offline support requires deliberate cache design. You cannot cache everything, so you have to decide which pages and assets matter most if a user loses connectivity. A news app might cache the last ten articles. A productivity tool might cache the entire local state. A simple marketing site might just cache the homepage and a fallback page that explains the user is offline.

Libraries like Workbox handle most of this without writing service worker logic by hand. Next.js, Vite, and other build tools have Workbox integrations that generate a service worker from your build output.

Background sync and push notifications

The service worker also enables two features that ordinary websites cannot have. Background sync lets the app queue actions taken while offline and replay them when connectivity returns, so a form submission does not just vanish because the user had no signal. Push notifications let a server send a message to the device even when the app is not open, the same mechanism native apps use.

Both require explicit user permission and both require HTTPS. Users are accustomed to permission prompts from native apps; the same expectation applies here.

The HTTPS Requirement

Browsers enforce HTTPS as a hard requirement for service workers. The reasoning is straightforward: a service worker that intercepts all network requests on an insecure origin would be trivial to replace with a malicious version via a network attacker. HTTPS guarantees the service worker file itself arrived intact and came from the domain it claims to represent.

In practice this is rarely a barrier. Free certificates from Let's Encrypt are issued automatically on every major hosting platform. If you are on Vercel, Netlify, or Cloudflare Pages, HTTPS is on by default. If you need a refresher on how TLS works under the hood, our HTTPS and SSL guide covers the full handshake.

The Install Prompt

When a site meets all three criteria, the browser fires a beforeinstallprompt event. You can listen for this event, hold onto it, and trigger the install prompt at a moment that makes sense in your app's flow rather than the moment the user first arrives.

On iOS, the process is different. Safari does not fire beforeinstallprompt. Users must manually tap the share icon and select “Add to Home Screen.” This has improved in recent iOS versions but remains a meaningful difference in the install experience between platforms.

After installation, the app appears in the device's app launcher. On desktop it appears in the applications list and can be pinned to the taskbar. The user has no way to tell from the icon whether they are looking at a native app or a PWA.

When a PWA Makes Sense

PWAs are a good fit when users interact with a site repeatedly, the site has a meaningful experience to offer without network access, and the team wants a single codebase that works across devices without separate App Store submissions.

They are less appropriate for simple informational sites. Adding a service worker to a brochure site that changes rarely and does not need offline support adds complexity without a meaningful benefit. The same applies to sites that pull heavily from real-time data where serving cached content would actively mislead the user.

The bar for a native app is higher: if the app needs deep hardware access (camera, sensors, Bluetooth, NFC in complex configurations), a native shell gives more reliable access. For most business applications, content tools, and productivity apps, a PWA covers the requirements without the friction of an app store review process.

Prompting an AI to Build a PWA-Ready Site

If you are using an AI assistant to generate or scaffold your site, the default output will not include PWA support. Most AI-generated projects produce a working web app with no manifest, no service worker, and no consideration for offline behavior. You have to ask for it explicitly, and the more specific you are, the better the result.

Start by naming your framework. “Add PWA support” is ambiguous. “Add PWA support to this Next.js 14 app using next-pwa and Workbox” gives the AI enough context to generate configuration that actually fits your project. The same applies to Vite (use vite-plugin-pwa), Create React App (largely deprecated but still in the wild), or a plain HTML site where the service worker must be registered manually.

Ask for a complete manifest, not a skeleton. AI tools frequently generate a manifest.json with placeholder values and a single low-resolution icon. Tell it to include icons at 192px and 512px as a minimum, set display to standalone, specify a theme_color that matches your brand, and set background_color to avoid a flash on launch. If you leave those details unspecified, they will be wrong or missing.

Be explicit about caching strategy. A prompt like “cache static assets at build time and use a network-first strategy for API routes” produces a service worker with deliberate behavior. Without that instruction, the AI will often generate either no caching at all or an aggressive cache-everything approach that serves stale data from dynamic endpoints.

After the AI generates the code, verify the result with Lighthouse. Open Chrome DevTools, run a Lighthouse audit on your deployed site, and check the PWA category. It will tell you exactly which requirements are missing or misconfigured. Common failures from AI-generated setups include a manifest that is not linked correctly in the HTML, icons that do not meet the minimum size, and a service worker that is registered but does not actually cache anything. Treat the Lighthouse report as the source of truth, not the AI's confirmation that the setup is complete.

Practical Takeaways

  • All three pillars are required. A manifest without a service worker is not a PWA. A service worker without HTTPS will not activate. Check all three before expecting an install prompt.
  • Use Workbox rather than writing service workers by hand. Cache invalidation and update lifecycle bugs are common and subtle. Workbox handles them with tested, documented strategies.
  • Design your cache deliberately. Decide which assets use cache-first, which use network-first, and which pages you want available offline. Caching everything by default leads to stale content and bloated storage.
  • Test on a real device. Service worker behavior, install prompts, and offline fallbacks behave differently in browser DevTools than on an actual mobile device on a real network.
  • Account for iOS. Plan a visible prompt or instructions for Safari users, since the automatic install banner does not appear on iPhone.
  • Version your service worker. When you update the cached assets, the new service worker must wait for all tabs running the old version to close before it takes control. Build this into your deployment process so users do not get stuck on stale code indefinitely.

A PWA turns a web project into something users keep on their device. The technical requirements are well-defined, the tooling is mature, and the result works across every platform with a single deployment. If your project involves repeat visits, offline scenarios, or a mobile-first audience and you want to evaluate whether a PWA makes sense for it, we can walk through the architecture with you at Code43.

PWAs rely on HTTPS for every background feature they offer. Read our guide on how HTTPS and TLS work to understand the security layer underneath, or see how CDNs pair with service worker caching to maximize performance for global audiences.

Need help with your infrastructure?

Whether it's DNS, deployment, or full-stack architecture — Code43 can help you get it right.

Book a Consultation
Your Website Can Be an App