---
title: "Progressive Web App (PWA) Guide"
version: 3.8.1
lastUpdated: 2026-05-13
---

# Progressive Web App (PWA) Guide

OmniRoute ships as a fully installable Progressive Web App. When you access the dashboard from any mobile browser — Android (Chrome) or iOS (Safari) — you can "Add to Home Screen" and get a native app-like experience with no app store required.

## What Is a PWA?

A Progressive Web App turns the OmniRoute web dashboard into something that looks and feels like a native mobile app. Once installed, it:

- Launches from your home screen with its own icon
- Opens fullscreen — no browser address bar or tab UI
- Works offline with a dedicated connectivity page
- Caches static assets for faster loading
- Supports both portrait and landscape orientations

## Installation

### Android (Chrome)

1. Open the OmniRoute dashboard in Chrome: `http://YOUR_IP:20128`
2. Chrome will show an **"Add OmniRoute to Home screen"** banner automatically, or:
   - Tap the **⋮** menu (three dots) → **"Add to Home screen"** or **"Install app"**
3. Confirm the prompt
4. OmniRoute appears on your home screen as a standalone app

### iOS (Safari)

1. Open the OmniRoute dashboard in Safari: `http://YOUR_IP:20128`
2. Tap the **Share** button (box with arrow)
3. Scroll down and tap **"Add to Home Screen"**
4. Name it (defaults to "OmniRoute") and tap **Add**
5. OmniRoute appears on your home screen with the app icon

### Desktop (Chrome / Edge)

1. Open the OmniRoute dashboard
2. Click the **install icon** in the address bar (or ⋮ → "Install OmniRoute...")
3. Confirm the prompt
4. OmniRoute opens as a standalone window — no tabs, no address bar

## Features

### Fullscreen Experience

The manifest is configured with `display: "fullscreen"`, which means the installed app uses the entire screen — no browser chrome, no status bar overlap. This makes the dashboard feel truly native.

### Offline Support

OmniRoute includes a service worker (`sw.js`) that provides intelligent caching:

| Asset Type                                              | Strategy                           | Behavior                                                                     |
| ------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------- |
| **App Shell**                                           | Cache-first                        | `/`, `/offline`, manifest, and icons are pre-cached on install               |
| **Static assets** (CSS, JS, images, fonts)              | Network-first with cache fallback  | Fetches fresh from the network; falls back to cache if offline               |
| **Next.js bundles** (`/_next/`)                         | Network-first with cache update    | Fetches from network and updates cache; serves cached version if offline     |
| **Navigation requests**                                 | Network-only with offline fallback | Always fetches from network; shows `/offline` page if network is unavailable |
| **API routes** (`/api/`, `/a2a`, `/dashboard/endpoint`) | Bypass (never cached)              | Always goes directly to the server — never intercepted by the service worker |

### Offline Page

When the network is unavailable and a user navigates to a new page, the service worker serves a dedicated `/offline` page that:

- Displays a clear **"Connectivity Issue"** message
- Shows a live **online/offline status indicator** that updates in real time
- Provides a **"Retry Connection"** button to reload when connectivity returns
- Links to the **Status Page** for diagnostics

### App Icons

OmniRoute provides icons optimized for each platform:

| File                   | Size             | Used By                               |
| ---------------------- | ---------------- | ------------------------------------- |
| `icon-512.png`         | 512×512          | Android install prompt, splash screen |
| `apple-touch-icon.png` | 180×180          | iOS home screen icon                  |
| `icon-192.svg`         | 192×192 (vector) | Android adaptive icon                 |
| `apple-touch-icon.svg` | 180×180 (vector) | Apple fallback                        |
| `favicon.svg`          | Vector           | Browser tabs                          |
| `favicon.ico`          | Multi-size       | Legacy browsers                       |

### Automatic Registration

The service worker is registered automatically via the `<PwaRegister />` component in the root layout. No user action is needed — the app becomes installable as soon as the browser detects the valid manifest and service worker.

## Technical Architecture

### Web App Manifest (`manifest.webmanifest`)

Generated by Next.js via `src/app/manifest.ts`:

```json
{
  "name": "OmniRoute",
  "short_name": "OmniRoute",
  "description": "OmniRoute is an AI gateway for multi-provider LLMs. One endpoint for all your AI providers.",
  "start_url": "/",
  "scope": "/",
  "display": "fullscreen",
  "orientation": "any",
  "background_color": "#0b0f1a",
  "theme_color": "#0b0f1a",
  "icons": [
    { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" },
    { "src": "/apple-touch-icon.png", "sizes": "180x180", "type": "image/png" }
  ]
}
```

### Service Worker (`public/sw.js`)

A vanilla service worker (no framework dependencies) with:

- **Install phase**: Pre-caches the app shell (root, offline page, manifest, icons)
- **Activate phase**: Cleans up old cache versions and claims all clients
- **Fetch phase**: Intelligent routing based on request type (navigation, static asset, API)
- **Cache versioning**: `omniroute-pwa-v2` — bump this to force a fresh cache on update

### Layout Metadata (`src/app/layout.tsx`)

The root layout provides all the meta tags required for PWA compliance:

- `manifest` link to `/manifest.webmanifest`
- `apple-web-app-capable: true` for iOS standalone mode
- `apple-web-app-status-bar-style: black-translucent`
- `mobile-web-app-capable: yes` for Android Chrome
- `theme-color: #0b0f1a`
- `viewport-fit: cover` for edge-to-edge rendering

### Component: `PwaRegister`

Located at `src/shared/components/PwaRegister.tsx`, this client component:

1. Runs on mount (client-side only)
2. Checks for `serviceWorker` support in the browser
3. Registers `/sw.js` silently (errors are swallowed to avoid blocking the app)
4. Renders nothing (`return null`) — it's a side-effect-only component

## Use With Termux (Android)

When running OmniRoute on Android via Termux, the PWA works seamlessly:

1. Start OmniRoute in Termux: `npx omniroute`
2. Open Chrome on the same phone: `http://localhost:20128`
3. Install the PWA via "Add to Home Screen"
4. The PWA connects to the local Termux server — everything runs on-device

This combination means your Android phone is both the **server** (Termux) and the **client** (PWA) — a complete self-contained AI gateway.

## Use From Other Devices

Install the PWA on any device that has browser access to your OmniRoute server:

- **Another phone/tablet**: Navigate to `http://PHONE_IP:20128` and install the PWA
- **Laptop**: Open Chrome/Edge and install it as a desktop PWA
- **Smart TV with browser**: Access the dashboard fullscreen

## Customization

### Instance Name

The PWA title respects the **Instance Name** setting from `Dashboard → Settings`. If you rename your instance to "My AI Gateway", the installed PWA will show that name.

### Custom Favicon

If you upload a custom favicon via `Dashboard → Settings`, the PWA icon on desktop will reflect the custom icon. Mobile home screen icons use the pre-built `icon-512.png` and `apple-touch-icon.png` files.

## Limitations

- **No push notifications** — The service worker does not implement the Push API. Notifications are handled by the Electron app instead.
- **No background sync** — Offline actions are not queued for replay. The PWA is primarily a dashboard viewer.
- **iOS restrictions** — Safari on iOS does not support all PWA features (e.g., install prompts are manual, and background service workers are limited).
- **Cache size** — The service worker caches static assets only. Large response payloads from `/api/` routes are never cached.
- **Custom icons on mobile** — Changing the favicon in settings does not update the home screen icon on mobile (this requires regenerating the PWA icons).

## Files Reference

| File                                    | Purpose                                                          |
| --------------------------------------- | ---------------------------------------------------------------- |
| `src/app/manifest.ts`                   | Next.js manifest route (generates `manifest.webmanifest`)        |
| `public/sw.js`                          | Service worker with caching logic                                |
| `src/shared/components/PwaRegister.tsx` | Client component that registers the service worker               |
| `src/app/offline/page.tsx`              | Offline fallback page with live status indicator                 |
| `src/app/layout.tsx`                    | Root layout with PWA metadata (apple-web-app, theme-color, etc.) |
| `public/icon-512.png`                   | 512×512 PNG icon (Android, splash screen)                        |
| `public/apple-touch-icon.png`           | 180×180 PNG icon (iOS home screen)                               |
| `public/icon-192.svg`                   | 192×192 SVG icon (Android adaptive)                              |
| `public/apple-touch-icon.svg`           | 180×180 SVG icon (Apple fallback)                                |
