All articles

Technical

Managing WebSockets in Android TWAs

October 1, 2026 · 8 min read

The Challenge of Real-Time Connections on Mobile

WebSockets are highly efficient for real-time data exchange, such as chat applications, live dashboards, and collaborative platforms. While they run perfectly inside standard desktop browsers, running a WebSocket connection inside an Android Trusted Web Activity (TWA) introduces platform-specific challenges.

Mobile devices constantly cycle through varying network states, jump between Wi-Fi and mobile data, and aggressively put background applications to sleep to preserve battery life. To ensure a reliable user experience, your PWA's WebSocket architecture must be resilient, self-healing, and aware of the Android application lifecycle.

How Android Resource Management Impacts WebSockets

When a user minimises your TWA, locks their phone, or switches to another application, Android does not keep your web app's JavaScript runtime active indefinitely. The Chrome browser process hosting your TWA will eventually be throttled or suspended. When this happens, the active TCP connection behind your WebSocket is severed by the operating system or drops due to inactivity timeouts.

Because the app cannot listen to active events while suspended, the primary goal is not preventing the disconnection, but detecting the disconnection immediately upon resumption and establishing a fast, clean reconnection.

Understanding App Standby and CPU Throttling

Android places background apps into different standby buckets depending on usage frequency. When your TWA transitions to background mode, the operating system limits CPU execution and suspends networking resources. This means any active WebSocket will time out on the server side because the client can no longer respond to ping frames or keep-alive requests. Your server must be configured to gracefully clean up these dead connections without throwing errors.

Detecting Lifecycle Changes and Network Recovery

To rebuild a dropped WebSocket connection, you must monitor two primary triggers: the Page Visibility API (to catch when the app returns to the foreground) and the online/offline system events. The visibilitychange event tells you exactly when the user has re-opened your TWA. If the document visibility state changes from hidden to visible, your app should check the WebSocket state and reconnect if necessary.

Similarly, the browser's network status API lets you know when the device gains or loses connectivity. By binding listeners to the online and offline events, you can quickly reset connections when transitions occur.

Implementing a Self-Healing WebSocket Wrapper

A simple new WebSocket() call is insufficient for a production-grade TWA. You must wrap your WebSocket initialisation in a manager that handles reconnect attempts with exponential backoff, preventing your servers from being overwhelmed if your database or API is temporarily offline. Here is a clean implementation pattern for a resilient WebSocket wrapper:

class ResilientWebSocket { constructor(url) { this.url = url; this.ws = null; this.reconnectAttempts = 0; this.maxDelay = 30000; this.connect(); this.setupListeners(); } connect() { if (this.ws && this.ws.readyState !== WebSocket.CLOSED) return; this.ws = new WebSocket(this.url); this.ws.onopen = () => { console.log("WebSocket connection established."); this.reconnectAttempts = 0; }; this.ws.onclose = () => { this.scheduleReconnect(); }; this.ws.onerror = (err) => { console.error("WebSocket error:", err); }; } scheduleReconnect() { const delay = Math.min(Math.pow(2, this.reconnectAttempts) * 1000, this.maxDelay); this.reconnectAttempts++; setTimeout(() => { console.log("Attempting reconnection..."); this.connect(); }, delay); } setupListeners() { document.addEventListener("visibilitychange", () => { if (document.visibilityState === "visible") { this.connect(); } }); window.addEventListener("online", () => { this.connect(); }); } }

Exponential Backoff Strategy Explained

Exponential backoff is a standard algorithm that doubles the wait time between each reconnection attempt. If the connection fails, the client waits 1 second, then 2 seconds, then 4, then 8, up to a maximum cap (such as 30 seconds). This ensures that if your server experiences a brief outage, thousands of installed TWA apps will not repeatedly bombard your server every single second, allowing your infrastructure to recover.

Handling Heartbeats and Silently Dropped Connections

Mobile networks sometimes drop connections silently without triggering the native socket close event. This creates a ghost connection where your client believes it is online, but no data can pass. To combat this, you must run an active heartbeat (ping/pong) mechanism from your client or server.

Using a standard interval, send a small text frame (like the string ping) from the client to the server every 30 seconds. If the server does not respond with a corresponding pong frame within a set window, manually call ws.close() to trigger your reconnection logic.

WebSocket Lifecycle and Recovery Strategy Matrix

Managing the WebSocket state based on device behaviour is critical. The following table highlights the exact state transitions and the required client-side action:

Device EventWebSocket StateRequired Action
TWA MinimizedActive to SuspendedServer-side connection cleanup occurs; client pauses execution.
TWA RestoredDisconnectedVerify Page Visibility state and immediately trigger connection.
Network DroppedOfflineDo not reconnect immediately; listen for online event.
Network RestoredOffline to OnlineReset backoff counter and execute immediate reconnection.

Ready to ship your Android app?

Paste your PWA URL, get a signed APK and a Google Play ready AAB in minutes.

Build my app