Guides8 min read

Offline support and offline screens in Capacitor

Real apps lose the network. How to detect connectivity, cache the app shell, show a clean offline screen, and keep OTA updates working across connection drops in a Capacitor app.

Phones lose signal — in elevators, on planes, in the countryside, on a bad carrier. An app that shows a blank screen the moment the network drops feels broken. This guide covers building real offline support into a Capacitor app: detecting connectivity, caching the app shell, showing a clean offline state, and keeping OTA updates working across connection drops.

Capacitor gives you a head start: the web bundle is already on the device, so your UI shell loads offline by default. The work is handling data gracefully when the network isn't there.

1. Detect connectivity

Use the Network plugin to know the current state and react to changes:

import { Network } from '@capacitor/network';

const status = await Network.getStatus();
Network.addListener('networkStatusChange', (s) => {
  setOnline(s.connected);
});

2. Show a real offline state, not an error

When offline, degrade gracefully: serve cached data, disable actions that need the network with a clear explanation, and show a small persistent indicator rather than a full-screen error. A good offline state tells the user “you're offline, here's what still works.”

3. Cache what matters

Persist the data the user needs most recently viewed content, their profile, queued actions to replay when the connection returns. Store it in the platform storage (and secrets in the keystore — see secure token storage).

4. OTA updates and offline coexist cleanly

This is where the OTA model helps rather than hurts. The device always keeps its current bundle, so losing the network mid-check never breaks the app — the update simply doesn't apply yet and retries when connectivity returns:

import { OtaKit } from '@otakit/capacitor-plugin';

Network.addListener('networkStatusChange', (s) => {
  if (s.connected) OtaKit.check(); // resume the check when back online
});

See update error-handling UX for why a failed check should stay silent.

Test airplane mode deliberately: toggle it mid-flow, mid-download, mid-update. The behaviors you discover there — and the fixes — are almost all web-layer, so you can ship them over the air as you harden the app.

Where to go next

See background tasks for syncing queued work, and Events for the update lifecycle across reconnects.

Related docs