PWA & Browser APIs
PWA is a tiny addition to your app — and the browser APIs that make offline-first possible.
What PWA Actually Is
PWA is three small additions to your web app:
Web App Manifest
A JSON file that tells the browser the app is installable:
{
"name": "My App",
"short_name": "MyApp",
"start_url": "/",
"display": "standalone",
"icons": [{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" }]
}Linked in HTML: <link rel="manifest" href="/manifest.json" />
Install Prompt
Handle the browser's install prompt:
window.addEventListener("beforeinstallprompt", (e) => {
e.preventDefault();
window.deferredInstallPrompt = e;
});
async function installApp() {
await window.deferredInstallPrompt?.prompt();
const { outcome } = await window.deferredInstallPrompt.userChoice;
}HTTPS
Service Workers only work over HTTPS (or localhost).
That's It
PWA is not a framework, build tool, or magic that makes your app work offline. It's a manifest file, an optional install prompt, and a way to "install" your web app to the home screen.
When you "install" a PWA, the browser creates a shortcut and the app opens in a standalone window. That's all — it's still a web app. Installing doesn't download the app, make it work offline automatically, or give it native APIs.
PWA vs Offline Capability
| Feature | PWA | Offline Capability |
|---|---|---|
| Manifest file | Required | Not needed |
| Install prompt | Optional | Not needed |
| Service Worker | Required | Required |
| Assets cached | Yes | Yes |
| Data works offline | Not guaranteed | Required |
| App feels native | Yes | Not required |
Swoff's Position
PWA is a tiny addition to Swoff apps:
Swoff Core (offline app shell, versioned SW, data caching & sync)
+
PWA Layer (manifest + install prompt)
=
Installable Offline-Ready AppWe document PWA setup, but it's not the focus. The focus is offline capability through architecture. Every browser supports "Add to Home Screen" or "Create Shortcut" — PWA just provides a nicer prompt.
The Browser Offline Stack
Swoff is built on standard browser APIs — no frameworks, no libraries. These APIs are available in all modern browsers.
Cache API
Store and retrieve network requests/responses.
const cache = await caches.open("my-cache-v1");
await cache.put(request, response);
const response = await cache.match(request);IndexedDB
Client-side database for structured data.
const request = indexedDB.open("my-db", 1);
request.onupgradeneeded = (e) => {
const db = e.target.result;
db.createObjectStore("todos", { keyPath: "id" });
};Fetch API
Make network requests.
const response = await fetch("/api/data");
const data = await response.json();Supporting APIs
| API | Purpose | Notes |
|---|---|---|
| LocalStorage | Simple key-value storage | Synchronous, ~5MB limit |
| SessionStorage | Like localStorage, cleared on close | Synchronous, ~5MB limit |
| Web App Manifest | PWA metadata (JSON file) | Not a JavaScript API |
Future APIs
| API | Purpose | Status |
|---|---|---|
| Background Sync | Defer network requests offline | Chrome/Edge only |
| Push API | Receive push notifications | Available, needs SW |
| File System Access | Read/write files on device | Chrome/Edge only |
Browser Support
| API | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Service Worker | Yes | Yes | Yes | Yes |
| Cache API | Yes | Yes | Yes | Yes |
| IndexedDB | Yes | Yes | Yes | Yes |
| Fetch | Yes | Yes | Yes | Yes |
| Background Sync | Yes | No | No¹ | Yes |
| Push API | Yes | Yes | Yes² | Yes |
¹ Background Sync is not supported on iOS Safari. Use the online event listener instead.
² Push API on iOS Safari requires iOS 16.4+ and standalone PWA mode (added to Home Screen).
See iOS Safari Limitations for detailed platform constraints.
Why No Libraries?
These APIs are stable, well-documented on MDN, sufficient for offline-first apps, and have zero bundle cost. There's no need for wrappers.
Next Steps
- Offline-First Architecture — how to build with these APIs
- iOS Safari Limitations — platform constraints
Swoff