# Low Level Design: Presence Service

Source: https://www.techinterview.org/post/3233470924/lld-presence-service/
Updated: 2026-04-18 · techinterview.org

## Presence States

- **online** — active heartbeat within the last 30 seconds

- **away** — active within the last 5 minutes but not in the last 30 seconds

- **offline** — no activity for more than 5 minutes

## Heartbeat Mechanism

Client sends a ping every 15 seconds. Server updates presence in Redis:


```
SETEX user:{id}:heartbeat 30 {timestamp}
```

The 30-second TTL ensures the key auto-expires if the client disconnects without an explicit logout.

## Status Derivation


```
GET user:{id}:heartbeat
  -> key exists, age < 30s  => online
  -> key exists, age < 5min => away
  -> key missing            => offline
```


## Presence Events and Fan-Out

On state change, publish to Redis channel:


```
PUBLISH presence:{user_id} {state}
```

A subscriber service maintains the friendship graph. On each presence event it fans out notifications to all friends with active WebSocket connections.

### High-Follower Fan-Out

For users with more than 10K followers, synchronous fan-out is too slow. Instead, push the event to an async fan-out queue (e.g., Kafka/SQS). Workers consume and deliver to followers in batches.

## Last-Seen Storage


```
UserPresence (
  user_id      BIGINT PRIMARY KEY,
  last_seen_at TIMESTAMP
)
```

Written to DB when a user transitions to offline, so last-seen can be displayed even for users who have been offline for days.

## Privacy

Each user has a per-account setting to hide their online status. If enabled, presence events are suppressed and API responses return `null` for that user.

## Presence Subscription

On app load, the client sends a list of contact user IDs. The server subscribes the client to those presence channels and streams state changes in real time.

## Batch Presence API

For rendering a contact list efficiently:


```
GET /presence/batch?user_ids=1,2,3,4,5

Response:
{
  "1": "online",
  "2": "away",
  "3": "offline"
}
```

Server performs a Redis pipeline MGET for all requested keys, derives states, and returns in a single response.

## Architecture Summary


```
Client  --heartbeat ping-->  API Server  --SETEX-->  Redis
                                             |
                                         PUBLISH presence:{uid}
                                             |
                                      Subscriber Service
                                             |
                                    Fan-out to friends via WS / queue
```


See also: [Meta Interview Guide 2026: Facebook, Instagram, WhatsApp Engineering](https://www.techinterview.org/post/3233460272/meta-interview-guide-2026-facebook-instagram-whatsapp-engineering/)

See also: [Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence](https://www.techinterview.org/post/3233460274/netflix-interview-guide-2026-streaming-architecture-recommendation-systems-and-engineering-excellence/)

See also: [LinkedIn Interview Guide 2026: Social Graph Engineering, Feed Ranking, and Professional Network Scale](https://www.techinterview.org/post/3233460278/linkedin-interview-guide-2026-social-graph-engineering-feed-ranking-and-professional-network-scale/)

See also: [Snap Interview Guide](https://www.techinterview.org/post/3233459923/snap-interview/)

See also: [Atlassian Interview Guide](https://www.techinterview.org/post/3233459919/atlassian-interview/)
