Progressive Web Apps for Students: Manifests, Service Workers, Offline Caching and Push

How do you make your project website installable, offline-capable, and able to send push notifications without the Play Store? Build it as a Progressive Web App. This guide walks through the web app manifest, the service worker lifecycle, a caching-strategy decision table, offline UX patterns, push notification architecture, iOS caveats, and a testing checklist - including the airplane-mode demo rehearsal.

Written by Projectech16 min readPublished
For B.E./B.Tech Computer Science and IT final-year students turning project websites into installable apps Topics: PWA, Service Workers, Web App Manifest, Cache API, Web Push, Lighthouse
Illustration of a smartphone with app tiles and an install arrow beside a laptop browser window, with caching layers, gears and cloud symbols.
Illustration generated for this guide.
In this guide

A Progressive Web App is a website that behaves like a native app: installable on the phone's home screen, working offline, and able to send push notifications — without going through the Play Store. For a final-year project, that is a powerful combination. Your examiner installs the project from the browser in ten seconds, the demo works even when the seminar-hall Wi-Fi collapses, and you never have to explain why the app "is not on the Play Store yet". Projects that live or die on reliability in bad network conditions — an offline note-taking app, a weather forecast dashboard used in the field, a habit tracker the user opens every morning — are natural PWA candidates.

This guide walks through turning an existing website into an installable PWA: the manifest, the service worker (explained as architecture, with registration described as steps rather than code to paste blindly), offline caching strategies with a decision table, background sync for queued actions, push notifications, and the testing checklist that catches the failures everyone hits.

A note on how this guide is written: you will find the manifest as JSON you can copy, because it is pure configuration. The service worker is described in prose and architecture instead of a paste-ready JavaScript file — deliberately. A copied service worker you do not understand will cache the wrong things and serve stale pages during your own demo; understanding the lifecycle first is what makes the offline behaviour reliable.

The three pieces of a PWA

A PWA is not a framework or a rewrite. It is your existing website plus three additions:

  1. A web app manifest — a JSON file describing the app: its name, icons, colours, and how it should launch. This is what makes the browser offer "Install app".
  2. A service worker — a JavaScript file the browser installs and runs in the background, separate from your pages. It intercepts network requests, which is what enables offline support, caching, and push notifications.
  3. HTTPS — service workers only run on secure origins (HTTPS, or localhost for development). No HTTPS, no PWA. If you have not set this up, read How to Get a Free SSL Certificate first.

The browser's installability checklist (what Chrome actually verifies before showing the install prompt) is: a manifest with a name, a 192px icon and a 512px icon, a start_url, a display mode, and a registered service worker with a fetch handler — all served over HTTPS. Miss any one and the install prompt silently never appears. That checklist is also your debugging order when installation does not work.

The manifest: your app's identity card

Create manifest.json (or manifest.webmanifest — same thing) at your site root:

{
  "name": "Campus Habit Tracker",
  "short_name": "HabitTracker",
  "description": "Track daily habits with streak analytics, online or offline.",
  "start_url": "/",
  "scope": "/",
  "display": "standalone",
  "orientation": "portrait",
  "background_color": "#ffffff",
  "theme_color": "#2563eb",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ]
}

Field-by-field, the parts that actually matter:

  • name vs short_name. name is the full title shown on the install prompt and splash screen; short_name is what appears under the home-screen icon, where space is tight (keep it under 12 characters).
  • start_url. The page that opens when the user launches the installed app. / is standard. If your app needs a query parameter to know it was launched installed (for analytics), that goes here — but keep it clean.
  • display: standalone. This is what makes it feel like an app instead of a browser tab: no URL bar, no browser chrome. The alternatives are fullscreen (games), minimal-ui (a slim browser bar), and browser (just a bookmark — not app-like at all).
  • theme_color. Colours the status bar / title bar on Android to match your app. A small detail examiners notice subconsciously: a mismatched status bar screams "website pretending to be an app".
  • Icons. You need at least 192px and 512px PNGs. "purpose": "any maskable" on the 512 icon tells Android it may crop the icon into different shapes (circle, squircle) — design your icon with safe padding around the edges so nothing important gets cropped. Generate icons from a single 1024px source with any image tool; do not hand-draw each size.

Link it from your HTML head with a link tag pointing at the manifest file, plus a theme-colour meta tag. That is the entire manifest integration — two lines.

The service worker: architecture, not magic

A service worker is a background JavaScript file with a lifecycle you must understand, because every offline bug is a lifecycle bug:

Registration. Your page asks the browser to install the service worker file (conventionally /sw.js at the site root so its scope covers the whole site). Registration is a one-time call the browser remembers; on subsequent visits the browser checks whether the file changed and updates it automatically. Do this after the page loads, not during — a slow registration should never block your first paint.

Install phase. On first registration (and on every update), the worker runs its install step. This is where you cache the app shell — the HTML, CSS, JavaScript, and icons the app needs to render. Think of it as packing a suitcase: everything the app needs to open offline goes in now.

Activate phase. After install, the new worker waits until all tabs using the old worker are closed, then activates. This "waiting" behaviour surprises everyone the first time: you deploy a fix, reload the page, and still see the old version, because the old worker is still controlling the open tab. During development, the browser's developer tools have an "update on reload" option for the service worker — turn it on and leave it on until launch.

Fetch interception. Once active, the worker sits between your pages and the network. Every request the page makes — HTML, images, API calls — passes through the worker's fetch handler first, and the worker decides: serve from cache, go to network, or try network and fall back to cache. This decision point is the entire offline story.

Mental model: the manifest tells the phone "this website is an app". The service worker tells the browser "here is how to behave when the network misbehaves". Everything else is detail.

Caching strategies: the decision table

The fetch handler can implement several strategies. Picking the wrong one is the most common PWA bug — a news feed cached like an app shell shows yesterday's headlines forever; an app shell fetched like live data fails offline. Match the strategy to the resource:

Strategy How it works Use for Danger
Cache first Serve from cache; go to network only on cache miss App shell (HTML/CSS/JS), icons, fonts — things that change only on deploy Stale content if you cache things that change often
Network first Try network; fall back to cache on failure API data, dashboard stats, user-generated content Slow on flaky networks; needs a timeout so it does not hang
Stale-while-revalidate Serve cached copy immediately, fetch fresh copy in background for next time Avatars, product images, article bodies — content where "fast now, fresh next visit" is the right tradeoff First visit after an update still shows old data
Network only Always network, never cache Login, payments, form submissions — anything that must never be replayed from cache Fails offline (correctly — do not cache these)
Cache only Always cache, never network Truly static assets with versioned filenames Useless for anything dynamic

For a typical student project — say the offline note-taking app with sync dashboard — the mapping is: app shell cache-first, the notes list network-first with cache fallback, note attachments stale-while-revalidate, and the sync endpoint network-only. Four strategies in one worker is normal; one strategy for everything is the mistake.

Versioning the cache. Name your caches with a version (app-shell-v1, data-v1). On activate, the new worker deletes caches from older versions. Without this, users accumulate stale caches across deploys and your "fix" never reaches them — the PWA equivalent of "have you tried clearing the cache", except your users will not know to try.

Offline UX: what the user sees with no network

Caching makes offline possible; design makes it usable. An app that silently shows a blank page offline has technically working caching and a failed demo. Handle three states explicitly:

  1. Fully offline, cached content available. The app opens and works with the last synced data. Show a small, honest banner: "Offline — showing data from 10:42 AM". Users forgive stale data; they do not forgive silent staleness.
  2. Offline, content not cached. Show a designed offline page (your own branded "You're offline" screen), not the browser's dinosaur. For a weather dashboard, this means cached last-known forecast plus the offline page for uncached cities — not a dead tab.
  3. Actions taken offline. Queue them. A habit check-in marked offline, a note written offline, a form submitted offline — store the action locally and sync when connectivity returns. This is the Background Sync pattern: the service worker holds a queue of pending requests and replays them when the browser reports the network is back. The UI rule is simple: confirm the action immediately ("Saved — will sync when online") rather than blocking on the network.

For the viva, this is your party trick: turn on airplane mode mid-demo and keep using the app. Examiners remember the project that survived airplane mode.

Push notifications: the architecture in brief

Push lets your server wake the app with a notification even when it is closed — deadline reminders for a habit tracker, price-drop alerts for an auction project like the online auction platform. The architecture has three parts:

  1. Subscription. The app asks the user for notification permission, then subscribes through the browser's push service, receiving a unique subscription endpoint (a URL) plus encryption keys. Your app sends this subscription to your server and stores it per user.
  2. Sending. When an event happens, your server POSTs an encrypted payload to each stored subscription endpoint. You never talk to the phone directly — the browser vendor's push service (Google's FCM for Chrome, Apple's for Safari) delivers it.
  3. Display. The service worker receives the push event in the background and shows the notification. This works even with the site closed, because the worker lives outside the page.

Two honest caveats for a student project. First, Web Push needs a backend that stores subscriptions and sends the POSTs — on a static-only free host you need a small server or serverless function for this. Second, iOS historically lagged on web push support; verify on the actual devices your examiners use rather than assuming. Implement push as the final PWA feature, not the first — manifest plus offline caching deliver most of the demo value.

iOS and Safari: the honest caveats

No PWA guide is complete without the Apple section, because your examiner may well carry an iPhone. The facts, without drama:

  • Installation works on iOS via Safari's Share menu → "Add to Home Screen". There is no automatic install prompt like Chrome's — you may need to tell users (a small "Install our app" hint banner, shown only on iOS, is the standard pattern).
  • Service workers and offline caching work on iOS. The offline story in this guide functions on iPhones.
  • Web Push on iOS arrived later than on Android and with more restrictions (the app must be installed to the home screen first, among others). If push notifications are a headline feature of your project, test the exact flow on a real iPhone running a current iOS version — do not assume it from Android behaviour.
  • Storage eviction. iOS is more aggressive about evicting cached data for sites the user has not opened recently. For a habit tracker opened daily this is irrelevant; for a rarely-opened utility it means the offline cache may be gone when the user returns after a month. Design for graceful re-caching, not permanent offline.

None of this disqualifies PWAs for student projects — it just means the real-device test in the checklist below should include an iPhone if your audience uses them.

Beyond the basics: shortcuts and share target

Once the core PWA works, two manifest features add genuine app-like polish for little effort:

App shortcuts let users long-press your home-screen icon and jump straight to key screens — "New note", "Today's habits", "Scan QR". They are declared in the manifest as a shortcuts array with names, short names, URLs, and icons. For a demo, one shortcut to the app's headline action ("Record expense", "Start quiz") shows the examiner you thought about the installed experience, not just the checkbox.

Web Share Target lets your app appear in the phone's share sheet — a user shares a URL or text from another app, and your PWA receives it. For a note-taking app ("save this link as a note") or a lost-and-found portal ("share this photo to report a found item"), this turns the PWA from a standalone app into a participant in the phone's ecosystem. It is a manifest declaration plus a route in your app that handles the incoming share — an afternoon's work with outsized demo impact.

Testing checklist: prove it before the demo

Open Chrome DevTools, Application tab — it shows the manifest, the service worker state, and the cache contents. Work through this list:

  • Manifest valid. DevTools shows the parsed name, icons, and theme colour with no errors. Broken JSON here fails silently everywhere else.
  • Install prompt appears. In DevTools you can trigger the installability check; on a real phone, the browser offers "Install app". If it never appears, re-check the installability list: HTTPS, both icon sizes, fetch handler present.
  • Offline app shell. DevTools Network tab → "Offline" checkbox → reload. The app shell must render. If it does not, the install-phase caching missed a file — check the cache contents in the Application tab.
  • Offline data. With the network off, previously viewed data (notes list, last forecast, habit history) must display with the staleness banner.
  • Update flow. Change a file, redeploy, reload with tabs open — confirm the new worker installs and activates (use "update on reload" in dev; in production, closing all tabs activates it). Confirm old caches are deleted.
  • Lighthouse PWA audit. Run it in DevTools. It checks installability, offline behaviour, and performance in one pass. Aim to clear every PWA-category check; the score gives you a number to quote in your report.
  • Real device test. Install on an actual Android phone from the hosted HTTPS URL. Emulators miss the install-prompt behaviour and icon rendering issues (maskable cropping especially). Include an iPhone if your audience uses one.
  • Airplane-mode demo rehearsal. The full demo flow, start to finish, with the network off. Whatever breaks here would have broken in front of the examiner.

Common failures and how to read them

Symptom Likely cause Fix
Install prompt never appears Missing icon size, no fetch handler, or not on HTTPS Walk the installability checklist top to bottom; DevTools Application tab names the failing item
Page shows old version after deploy Old worker still controlling open tabs; stale cache not versioned Close all tabs to activate the new worker; version cache names and delete old ones on activate
Offline reload shows browser error page App shell not cached at install, or the fetch handler has no cache fallback for navigation requests Cache the shell files during install; add a navigation-fallback to the cached shell or a custom offline page
API data never updates Cached with cache-first strategy by mistake Move API calls to network-first with a timeout and cache fallback
"Site cannot be installed" on iOS iOS installability rules differ; also verify the manifest link and icons Test on the actual iPhone; keep icons standard PNGs and the manifest minimal
Push notifications never arrive Subscription not stored server-side, or payload not encrypted correctly Log the subscription endpoint on the server; test sending with the push service's debugging tools before wiring app logic

Putting it together

The PWA upgrade path for an existing project site is: HTTPS first, then the manifest (an afternoon), then the service worker with a cache-first app shell and network-first data (the real work — a focused weekend), then offline UX polish, and push notifications last if the project earns them. Each step is independently shippable and demoable, which makes it ideal final-year-project scope: even "installable plus offline app shell" is a legitimate, defensible feature. More web project concepts that suit the PWA treatment are in the Web Development branch hub, and if your team is building this together, the Git and GitHub guide keeps the collaboration sane.

Workbox: when to reach for a library

Everything above describes a hand-written service worker, because understanding the lifecycle matters. In practice, Google's Workbox library wraps the same concepts in tested recipes: precaching the app shell becomes a one-line manifest injection at build time, and the caching strategies from the decision table become named strategies (CacheFirst, NetworkFirst, StaleWhileRevalidate) you attach to routes. For a Vite project, the vite-plugin-pwa package wires Workbox in with near-zero configuration and generates the service worker at build time.

The honest guidance: write the first service worker by hand for a small project so the lifecycle is concrete in your head, then use Workbox for anything bigger. A hand-written worker for a 50-route app accumulates edge cases; Workbox has already met them. Either way, the debugging checklist above applies unchanged — libraries do not exempt you from verifying the offline behaviour.

Performance side-effects worth knowing

A well-built PWA is usually faster than the website it came from, and the reasons are worth stating in your report: the app shell loads from the local cache instead of the network (near-instant repeat visits), repeat API responses served stale-while-revalidate eliminate loading spinners on familiar screens, and the install prompt plus splash screen remove the browser chrome for a perception of speed. The measurable version: run Lighthouse before and after the PWA conversion and quote the performance-score delta alongside the PWA checklist score. Just keep the cache honest — an app that feels fast because it shows week-old data without saying so has traded correctness for a metric.

More project guides

More in Web Development