Swoff Swoff

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

FeaturePWAOffline Capability
Manifest fileRequiredNot needed
Install promptOptionalNot needed
Service WorkerRequiredRequired
Assets cachedYesYes
Data works offlineNot guaranteedRequired
App feels nativeYesNot 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 App

We 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

APIPurposeNotes
LocalStorageSimple key-value storageSynchronous, ~5MB limit
SessionStorageLike localStorage, cleared on closeSynchronous, ~5MB limit
Web App ManifestPWA metadata (JSON file)Not a JavaScript API

Future APIs

APIPurposeStatus
Background SyncDefer network requests offlineChrome/Edge only
Push APIReceive push notificationsAvailable, needs SW
File System AccessRead/write files on deviceChrome/Edge only

Browser Support

APIChromeFirefoxSafariEdge
Service WorkerYesYesYesYes
Cache APIYesYesYesYes
IndexedDBYesYesYesYes
FetchYesYesYesYes
Background SyncYesNoNo¹Yes
Push APIYesYesYes²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

On this page