Building Real-Time Features in Mobile Applications
How to build real-time features in mobile apps — WebSockets, server-sent events, presence indicators, live updates, and managing connection lifecycle on mobile.
Strategic Systems Architect & Enterprise Software Developer
Real-time features — live chat, presence indicators, collaborative editing, live location tracking, instant notifications — make apps feel alive. Users expect messages to appear instantly, driver locations to update smoothly, and collaborative changes to reflect without refreshing.
Building real-time features on mobile is more nuanced than on web. Mobile connections drop, apps get backgrounded, and battery constraints limit how aggressively you can maintain connections. Here is how to build real-time features that work reliably in production.
Choosing Your Transport
The three main options for real-time communication are WebSockets, Server-Sent Events (SSE), and polling. Each fits different use cases.
WebSockets provide a persistent, bidirectional connection between client and server. Both sides can send messages at any time without the overhead of HTTP request/response cycles. WebSockets are the right choice for chat, collaborative features, and any scenario where both the client and server initiate communication.
The mobile-specific challenge with WebSockets is connection management. When the app goes to the background, the OS may suspend the socket connection. When the app returns to the foreground, you need to reconnect and synchronize any missed messages. This reconnection logic is where most real-time implementations get complicated.
Server-Sent Events provide a one-directional stream from server to client over HTTP. They are simpler than WebSockets and work well when the server pushes updates and the client only needs to listen — live scores, stock tickers, activity feeds. SSE has built-in reconnection logic, which simplifies the mobile lifecycle handling.
Polling sends regular HTTP requests to check for updates. It is the simplest to implement and the least efficient. Short polling (every few seconds) wastes bandwidth and battery. Long polling (holding a connection open until data is available) is more efficient but still has overhead. Use polling only when your update frequency is low (every 30+ seconds) and WebSocket infrastructure is not justified.
For most real-time features I build, WebSockets are the right choice. The bidirectional communication and low latency justify the additional complexity.
Connection Lifecycle on Mobile
The critical difference between real-time on web and mobile is the app lifecycle. Web apps run in a browser tab that stays active. Mobile apps get backgrounded, suspended, killed, and resumed constantly. Your real-time connection must handle all of these transitions.
When the app moves to the background, decide whether to maintain or close the WebSocket connection. For chat apps, maintaining the connection briefly (30-60 seconds) lets you receive messages for notification display. For non-essential updates, close the connection immediately to conserve battery.
On iOS, background execution is strictly limited. You get approximately 30 seconds of background time, after which the OS suspends your process. Use this window to close connections cleanly and persist any pending state. For incoming messages while the app is backgrounded, rely on push notifications through APNs rather than maintaining a WebSocket connection.
On Android, background restrictions are more complex and vary by manufacturer. Samsung's aggressive battery management, for example, can kill background connections faster than stock Android. Use foreground services for features that genuinely need continuous connections (active delivery tracking, ongoing voice calls), but respect the platform's intent — most features should not run in the background.
When the app returns to the foreground, reconnect the WebSocket and synchronize state. This means requesting any messages or updates that occurred while disconnected. The server needs to support this — a sync endpoint that returns events after a given timestamp, or a message history API that the client calls on reconnection.
Building Reliable Message Delivery
Real-time does not mean "fire and forget." Users expect messages to be delivered, and they expect to know when delivery fails. Building reliable delivery on top of an unreliable network requires deliberate design.
Assign a unique ID to every message on the client before sending. When the server receives and processes the message, it sends an acknowledgment with the same ID. If the client does not receive an acknowledgment within a timeout, it retries. The server deduplicates by message ID, so retries are safe.
Maintain a local message queue on the device. When the user sends a message, it goes into the local queue with a status of "sending." When the server acknowledges receipt, the status changes to "sent." When the recipient reads it, the status changes to "read." The UI reflects these states — users see their message immediately with a subtle "sending" indicator that resolves to a checkmark on delivery.
For offline scenarios, messages queue locally and send when the connection is re-established. This overlaps with offline-first architecture — the sync queue for real-time messages follows the same patterns as offline data sync.
Handle message ordering carefully. Network latency means messages can arrive at the server in a different order than they were sent. Use client-side timestamps for display ordering and server-side timestamps for canonical ordering. When messages from multiple users arrive, sort by server timestamp to ensure all clients see the same order.
Scaling Considerations
Real-time connections are stateful, which makes scaling different from stateless HTTP APIs. Each connected client holds a WebSocket connection on a specific server instance, and the server must route messages to clients that may be connected to different instances.
Use a pub/sub system — Redis Pub/Sub, NATS, or a managed service like Ably or Pusher — to distribute messages across server instances. When a message arrives at one server, it publishes to the channel, and all server instances with subscribed clients receive and deliver it.
For room-based features (chat rooms, document collaboration), assign each room to a pub/sub channel. Clients subscribe to the channels they need. This keeps the message routing efficient — a message in room A is only delivered to clients in room A, not broadcast to every connected client.
Monitor your WebSocket connection counts, message throughput, and reconnection rates. A spike in reconnections often indicates network issues or server instability. Track message delivery latency (time from send to delivery) as an SLI — if p95 delivery time exceeds your threshold, investigate.
The real-time layer is often the most complex part of a mobile app's backend architecture. Build it as a separate service from your REST API so you can scale it independently. Real-time connections have different resource profiles than HTTP requests, and separating them lets you optimize each independently.
Consider managed real-time services for your first implementation. Services like Ably, Pusher, or Firebase Realtime Database handle the connection management, scaling, and reliability concerns so you can focus on your application features. Move to a self-hosted solution when the managed service costs exceed the engineering cost of running your own infrastructure.