
PWA Setup
How To Turn Any Website into a Secure Progressive Web App
A step-by-step guide to turning an existing website into a secure Progressive Web App. Covers HTTPS, manifests, service workers, caching strategy, updates, and permission hygiene with practical explanations.
PWAs fixed a few long-standing web issues. No app store gatekeepers. No rewrites. Just the web, behaving better than it used to. If you’ve ever wanted your site to feel more solid, more reliable, and a little harder to break, this is for you.
A quick bit of history, because it matters. Around 2015, Google started formalizing ideas that had already been floating around for years. Offline support. Installable websites. Smarter caching. Apple followed later. The result was the PWA. Not a new platform, just a stricter way of using existing web primitives. HTTPS. Service workers. Manifests. Boring names. Powerful outcomes.
Step 1: Serve everything over HTTPS
This is non-negotiable. Service workers will not register on insecure origins. If your site still runs on plain HTTP, the browser simply refuses to play along.
Most hosting providers make this easy now. If you’re using Cloudflare, Vercel, Netlify, or a modern VPS with Let’s Encrypt, you’re probably already covered. The important thing is consistency. No mixed content. No stray HTTP images or scripts. Browsers notice. Quietly.
Step 2: Add a web app manifest
The manifest is a small JSON file that tells the browser how your site should behave when installed. Name, icon, colors, start URL. Nothing dramatic. Just metadata, but metadata browsers actually respect.
{
"name": "My Website",
"short_name": "Website",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#111111",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}Link it in your HTML head, and that’s it. No build step required.
<link rel="manifest" href="/manifest.json">Step 3: Register a service worker
This is where the real work happens. Service workers sit between your site and the network. They decide what gets cached, what gets fetched, and what happens when the network disappears.
Register it once, usually near the bottom of your main JavaScript file.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}If that line feels underwhelming, good. Most good infrastructure is.
Step 4: Cache carefully, not aggressively
A big mistake people make with PWAs is caching too much, too early. A secure PWA is predictable. Users should know when content updates and when it doesn’t.
Start small. Cache your core assets. HTML shell. CSS. JavaScript bundles. Leave dynamic data alone unless you understand your invalidation strategy.
self.addEventListener('install', event => {
event.waitUntil(
caches.open('static-v1').then(cache => {
return cache.addAll([
'/',
'/styles.css',
'/app.js'
]);
})
);
});Version your caches. Delete old ones during activation. This is not optional. Browsers remember everything.
self.addEventListener('activate', event => {
const allowedCaches = ['static-v1'];
event.waitUntil(
caches.keys().then(keys => {
return Promise.all(
keys.map(key => {
if (!allowedCaches.includes(key)) {
return caches.delete(key);
}
})
);
})
);
});Step 5: Control updates explicitly
Service workers update in the background. That’s good for users and confusing for devs. A secure setup means being intentional about when new code takes over.
At minimum, handle the activate event and clean up outdated caches. More advanced setups add a refresh prompt. The key idea is respect. Don’t surprise people mid-session.
self.addEventListener('message', event => {
if (event.data === 'SKIP_WAITING') {
self.skipWaiting();
}
});// In your main app JS
if (navigator.serviceWorker) {
navigator.serviceWorker.addEventListener('controllerchange', () => {
window.location.reload();
});
}Step 6: Lock down permissions
Just because a PWA can request permissions doesn’t mean it should. Location, notifications, background sync. Ask only when necessary. Delay the prompt until the user understands why.
// Example: request notifications only after user action
button.addEventListener('click', async () => {
const permission = await Notification.requestPermission();
if (permission === 'granted') {
new Notification('Thanks for opting in');
}
});// Optional: check permission state before asking
navigator.permissions.query({ name: 'notifications' })
.then(result => {
console.log(result.state);
});Step 7: Test the boring cases
Turn off your internet. Load the site. Refresh. Close the tab. Reopen it. Install it. Uninstall it. Update it. Break it on purpose.
A secure PWA is not the one that demos well. It’s the one that behaves sensibly when nothing goes right.
// Offline-first fetch handler
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});Next Steps
From here, you can layer in background sync, smarter runtime caching, or tighter CSP headers. None of that is required on day one. The win is reliability, knowing that your site works even when the network doesn’t cooperate.
That’s what PWAs deliver. Not apps without app stores. Just the web, keeping its promises.
Tags
Join the Discussion
Enjoyed this? Ask questions, share your take (hot, lukewarm, or undecided), or follow the thread with people in real time. The community’s open, join us.
Published January 31, 2026 • Updated February 1, 2026
published
Latest in Step-by-Step

Turn Any YouTube Video Into Structured Notes Automatically
Feb 19, 2026

How To Turn Any Website into a Secure Progressive Web App
Jan 31, 2026

How to Build Your First AI Assistant Step by Step
Jan 26, 2026

How to Run Your Own AI Model Locally
Dec 9, 2025

Secure Your Accounts After an AI Phishing Attempt
Dec 8, 2025
Right Now in Tech

Court Tosses Musk’s Claim That OpenAI Stole xAI Trade Secrets
Feb 26, 2026

Meta’s Age Verification Push Reignites Online Anonymity Debate
Feb 23, 2026

Substack Adds Polymarket Tools. Journalists Have Questions.
Feb 20, 2026

Netflix Ends Support for PlayStation 3 Streaming App
Feb 18, 2026

The Internet Archive Is Getting Caught in the AI Scraping War
Feb 5, 2026