Clarity TLDR: A PWA is a regular website plus two files: a web app manifest (makes it installable) and a service worker (makes it work offline). Everything else — HTTPS, responsive design, fast loading — is just a well-built site. Both files, ready to copy, are below.
Most “How to create a PWA” tutorials bury you in concepts before showing a single line of code. This one shows the code first, because that’s all a PWA structurally is: your existing site, served over HTTPS, with a manifest file and a service worker.
What is a Progressive Web App?
A Progressive Web App (PWA) is a website that browsers can install and launch like a native app, with an icon on the home screen, its own window (no browser chrome), and the ability to work offline. It’s built with ordinary HTML, CSS, and JavaScript — no app store, no separate codebase for Android and iOS.
What does a site need to qualify as a PWA?
- Served over HTTPS — service workers only run on secure connections.
- A web app manifest — a JSON file describing the app’s name, icons, and colors.
- A registered service worker — JavaScript that controls caching and offline behavior.
- At least one 192×192 and one 512×512 icon for the manifest.
That’s the entire checklist. If you have those four things, browsers treat your site as installable.
Step 1: Add the web app manifest
Create a file called manifest.json in your site root:
{
"name": "My App — Full Name",
"short_name": "MyApp",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#1e6fd9",
"icons": [
{ "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" }
]
}
Then link it in your page’s <head>:
<link rel="manifest" href="/manifest.json">
display: "standalone" is what makes the installed app open in its own window instead of a browser tab. short_name is the label under the home-screen icon.
Step 2: Add the service worker
Create sw.js in your site root. This minimal version caches your core assets on first visit and serves them offline afterward:
// sw.js — minimal cache-first service worker
const CACHE = "myapp-v1";
const ASSETS = ["/", "/css/style.css", "/js/app.js", "/icons/icon-192.png"];
self.addEventListener("install", e => {
e.waitUntil(caches.open(CACHE).then(c => c.addAll(ASSETS)));
});
self.addEventListener("fetch", e => {
e.respondWith(
caches.match(e.request).then(cached => cached || fetch(e.request))
);
});
Then register it from your page — this can go in your existing JS or a small inline script:
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/sw.js");
}
One rule to remember: the service worker can only control pages at or below its own path. Put sw.js in the root and it covers your whole site.
Step 3: Verify it’s installable
Open Chrome DevTools → Application tab → Manifest. If there are no errors and the install criteria are met, Chrome will show an install prompt — and the address bar will show an install icon. If DevTools says “no matching service worker,” check that sw.js is registered and served from the root over HTTPS.
Step 4: Test with Lighthouse
Run the Lighthouse audit (DevTools → Lighthouse tab, or npx lighthouse https://yourdomain.com). Google’s PWA criteria are checked automatically. Don’t chase a 100 score — the install and offline checks are what matter for PWA functionality.
Do you need React, Angular, or Vue?
No. PWAs are framework-agnostic because the manifest and service worker are plain files served alongside whatever your site is built with. Use a framework if you already use one. If your caching needs grow beyond a few files, look at Workbox — Google’s library that generates service workers for you.
The whole thing, in one paragraph
Add manifest.json, link it in your head, add sw.js, register it, serve over HTTPS. That’s a PWA. Everything beyond that is normal web development.



