Skip to main content

📱 PWA Principles & Best Practices

What if a website could be installed to a home screen, launch full-screen with its own icon, load instantly on the subway with no signal, and still be nothing more than HTML, CSS, and JavaScript served from a URL? That is a Progressive Web App — and in this lesson you'll learn exactly what makes one, so the next three lessons can show you how to build it.

Week 14 · Thursday: Progressive Web Apps · Lecture 1

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Define a PWA and explain the three qualities that describe one: reliable, fast, and installable
  • Name the three technical pillars every PWA is built on — HTTPS, a web app manifest, and a service worker — and say what each provides
  • Author a valid manifest.json with the required members a browser needs to offer installation
  • List the browser installability criteria and describe how the service worker "sits between" the app and the network
  • Run a Lighthouse PWA audit and read its report to find what is missing
  • Apply progressive-enhancement best practices so the app works for every user

Estimated Time: 55 minutes

Project: Write a complete web app manifest and sketch the installability checklist for a demo app.

In This Lesson

What Is a PWA?

A Progressive Web App (PWA) is a web app — built with the same HTML, CSS, and JavaScript you already know — that uses modern browser capabilities to deliver an experience close to a native mobile or desktop app. It can be installed to a device, run offline, and feel like a real app: full-screen, with its own icon, its own launch splash, and no browser address bar.

The word "progressive" is the key. A PWA is built with progressive enhancement: the core experience works in any browser, and each modern capability the browser supports layers on extra polish. An older browser that has never heard of a service worker still gets a perfectly functional website; a modern browser gets the installable, offline-capable app on top.

📖 Not a framework, not an app store

A PWA is not a library you install or a special file format. It is a set of practices and browser APIs applied to an ordinary website. There is no PWA compiler and no PWA app store — the "install" happens straight from the browser, and updates ship the moment you deploy, with no review queue.

Why they matter

PWAs bridge a real gap. Native apps are fast and installable but cost a lot to build twice (iOS and Android), must pass store review, and require users to commit to a download. Websites reach everyone instantly by URL but historically broke the moment the network did. PWAs give you one codebase that reaches every platform through a link and earns a home-screen icon:

Traditional websiteNative appPWA
Works offline
Installable icon
Reachable by URL
No app-store review
One codebase, every platform

The Three Qualities

Google's original framing describes a great PWA with three adjectives. They are worth memorizing because every technical decision you'll make maps back to one of them.

Three qualities of a PWA: reliable, fast, and engaging 🛡️ Reliable loads on any network Fast responds instantly Engaging feels like an app
Every PWA technique — caching, the manifest, service workers — serves one of these three goals.

🛡️ Reliable

The app loads and stays usable regardless of network conditions — a strong signal, a flaky one, or none at all. It never shows the browser's dreaded "no internet" dinosaur. Reliability is delivered by the service worker caching the app's shell so a repeat visit works even with the radio off.

⚡ Fast

The app responds to interactions quickly and animates smoothly. Users abandon slow pages; research consistently shows conversions drop as load time climbs. A PWA gets its speed by serving cached assets instantly instead of re-downloading them on every visit.

✨ Engaging

The app feels like a natural part of the device. Once installed it launches from the home screen in its own window — no address bar, its own icon, a themed status bar — and can re-engage users through push notifications. This "app-like" feel comes from the web app manifest.

The Three Technical Pillars

Those three qualities rest on three concrete, non-negotiable technical requirements. If any one is missing, you do not have a PWA — the browser will not offer to install it.

graph TD A["Progressive Web App"] --> B["HTTPS
secure origin"] A --> C["Web App Manifest
manifest.json"] A --> D["Service Worker
service-worker.js"] B --> E["Encrypts traffic & unlocks modern APIs"] C --> F["Metadata for install & app-like launch"] D --> G["Caching, offline, background tasks"]

1. HTTPS — a secure origin

A PWA must be served over HTTPS (the one exception is localhost during development). Two reasons: a service worker is a powerful man-in-the-middle over your network traffic, so the browser only allows it on a connection that itself cannot be tampered with; and many of the modern APIs a PWA relies on are gated behind a "secure context." Free certificates from Let's Encrypt, and automatic HTTPS from hosts like Netlify or Vercel, make this a solved problem.

2. Web App Manifest — the identity card

The manifest is a small JSON file that tells the browser who your app is: its name, its icons, what color to paint the toolbar, and how it should launch. Without it, the browser has no icon to put on the home screen and no name to show. We build one in full in the next section.

3. Service Worker — the engine

The service worker is a JavaScript file that runs in a separate background thread, has no access to the DOM, and acts as a programmable network proxy sitting between your pages and the network. It is what makes offline possible. Think of it as a receptionist stationed between your app and the internet:

The service worker sits between the app and the network, intercepting requests Your App (the page) Service Worker intercepts requests 🌐 Network 📦 Cache
Every network request from the app passes through the service worker, which decides whether to answer from the cache or go to the network.

The Web App Manifest

The manifest is a JSON file — conventionally named manifest.json or manifest.webmanifest — that you link from the <head> of every page. Here is a complete, realistic example with each member explained.

{
  "name": "Weather Now",
  "short_name": "Weather",
  "description": "Fast, offline-capable local weather forecasts.",
  "start_url": "/?source=pwa",
  "scope": "/",
  "display": "standalone",
  "orientation": "portrait",
  "background_color": "#0f172a",
  "theme_color": "#3b82f6",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-maskable.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

Link it in your HTML <head>, and hint the theme color for browsers that read it before the manifest loads:

<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#3b82f6">

The members that matter

MemberRequired?What it does
nameFull app name, shown on the install prompt and splash screen
short_nameRecommendedShort label used under the home-screen icon where space is tight
start_urlThe URL that opens when the app is launched from its icon
iconsHome-screen and splash images; needs at least a 192px and a 512px PNG
displayRecommendedHow it launches: standalone, fullscreen, minimal-ui, or browser
theme_colorRecommendedColor of the toolbar / status bar in the installed app
background_colorRecommendedSplash-screen background shown while the app boots
scopeOptionalThe set of URLs considered "inside" the app

💡 What "display: standalone" buys you

With "display": "standalone", the installed app opens in its own window with no browser address bar or tabs — the single change that most makes a website feel like a native app. Use fullscreen for immersive games, and minimal-ui when you still want minimal navigation controls.

📖 Maskable icons

Android may crop your icon into a circle, squircle, or rounded square. An icon marked "purpose": "maskable" includes a safe padding zone so nothing important gets clipped. Provide one alongside your standard icons to avoid an awkwardly cropped logo.

Installability & Lighthouse

The browser will only offer to install your app — or fire the beforeinstallprompt event — when a specific checklist is satisfied. These are the installability criteria:

  • Served over HTTPS (or localhost)
  • Has a linked web app manifest with name/short_name, a valid start_url, a display of standalone/fullscreen/minimal-ui, and icons including at least 192px and 512px
  • Registers a service worker with a fetch handler (so the app can respond when offline)
  • The user has shown some engagement with the page

Auditing with Lighthouse

Lighthouse is an automated auditing tool built into Chrome DevTools (open DevTools → Lighthouse tab) and available as a CLI. It scores Performance, Accessibility, Best Practices, SEO, and runs PWA-specific checks — telling you exactly which installability requirement is missing and why.

Example Lighthouse PWA findings

✔ Registers a service worker that controls page and start_url
✔ Web app manifest and service worker meet the installability requirements
✖ Does not provide a valid apple-touch-icon
✖ Manifest doesn't have a maskable icon

Treat a red mark as a to-do item, not a failure. Lighthouse turns "is this a real PWA?" from an opinion into a checklist you can drive to green.

graph LR A["Deploy over HTTPS"] --> B["Add manifest.json"] B --> C["Register service worker"] C --> D["Run Lighthouse audit"] D --> E{"All checks green?"} E -->|No| F["Fix flagged item"] F --> D E -->|Yes| G["Browser offers Install"]

Best Practices & Pitfalls

✅ Do

  • Build with progressive enhancement — make the core content and features work without a service worker, then layer PWA capabilities on top
  • Serve everything over HTTPS from the start
  • Provide 192px and 512px icons, plus a maskable variant, so installs look sharp everywhere
  • Give start_url a tracking parameter (e.g. ?source=pwa) so analytics can measure launches from the installed app
  • Run Lighthouse regularly and keep the PWA checks green

❌ Don't

  • Don't treat "PWA" as a checkbox — a fast, reliable, well-designed app matters more than passing an audit
  • Don't make offline support an afterthought bolted on at the end; design for intermittent connectivity from the start
  • Don't forget the <meta name="theme-color"> tag; without it the toolbar color can look inconsistent
  • Don't assume every browser supports every API — always feature-detect (if ('serviceWorker' in navigator)) before using it

⚠️ HTTPS is not optional

A service worker registration silently fails on plain http:// (except localhost). If your offline features "just don't work" in production, the first thing to check is that the site is genuinely served over HTTPS — including every asset it loads.

Practice & Quiz

🏋️ Exercise 1: Write a valid manifest

Goal: Author a manifest.json for a note-taking app called "QuickNotes" that will pass the installability check. It must launch standalone, use a blue theme, and include the two required icon sizes.

💡 Hint

The installability minimum is: name (and/or short_name), a valid start_url, a display of standalone, and an icons array containing at least a 192×192 and a 512×512 PNG.

✅ Solution
{
  "name": "QuickNotes",
  "short_name": "QuickNotes",
  "start_url": "/?source=pwa",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#2563eb",
  "icons": [
    { "src": "/icons/note-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icons/note-512.png", "sizes": "512x512", "type": "image/png" }
  ]
}

🏋️ Exercise 2: Read a Lighthouse report

Goal: A colleague says "the install button never appears." Lighthouse shows: HTTPS ✔, manifest ✔ with valid icons, but "Does not register a service worker that controls page and start_url" ✖. Which of the three pillars is missing, and what must you add?

✅ Solution

The service worker pillar is missing. HTTPS and the manifest are both present, but the browser will not offer installation until a service worker with a fetch handler is registered and controlling the start_url. Adding and registering service-worker.js (the topic of the next lesson) turns the check green and enables the install prompt.

🎯 Quick Quiz

Question 1: Which three technical pillars must a PWA have?

Question 2: On which origin is a service worker allowed to run without HTTPS?

Question 3: What does "display": "standalone" in the manifest do?

Summary

🎉 Key Takeaways

  • A PWA is an ordinary web app enhanced to be installable, offline-capable, and app-like — no framework or app store required
  • Great PWAs are reliable, fast, and engaging; every technique serves one of those goals
  • Every PWA rests on three pillars: HTTPS, a web app manifest, and a service worker
  • The manifest supplies name, icons, start_url, display, and theme_color; at minimum you need 192px and 512px icons
  • The service worker is a proxy that sits between the app and the network, and it is what unlocks the install prompt
  • Lighthouse audits installability and tells you exactly what is missing

📚 Additional Resources

🚀 What's Next?

You now know what makes a PWA and which pieces it needs. The engine that delivers reliability and offline support is the service worker — so the next lesson gets hands-on: Service Workers Setup, where you'll register one, walk through its install → activate → fetch lifecycle, and implement your first caching strategies.

🎉 Well done!

You can now explain a PWA to anyone and write a manifest that passes the install check. Time to build the engine that powers it.