Find My Friends#
Problem statement (interviewer prompt)
Design Find My Friends: users opt-in to share their live location with chosen people. The watcher sees the latest position on a map with <5s lag, gets geofence alerts ("X arrived at home"), and an emergency-SOS button. Battery-efficient on the device side.
flowchart LR
A([User A])
B([User B])
LOC[Location Service]
WS[WebSocket Gateway]
PRES[(Presence KV)]
A -->|update loc| LOC --> PRES
B --> WS
WS --> PRES
PRES --> WS --> B
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
class A,B client;
class WS edge;
class LOC service;
class PRES datastore;
flowchart TB
subgraph Apps
A([User A app])
B([User B app])
end
subgraph Edge
LB
WS[WebSocket gateway<br/>persistent connection]
end
subgraph Loc[Location plane]
ING([Location Ingest])
BATCH[Adaptive batching<br/>battery aware]
GEO[(Presence KV<br/>user_id -> lat lng ts)]
HIST[(Optional history)]
end
subgraph Sharing[Sharing graph]
REL[Sharing Service]
ACL[(Permissions)]
GRP[Groups / families]
TEMP[Temp share link]
end
subgraph Fanout[Notify subscribers]
PUB[[Pub/Sub per-user channel]]
SUB[Subscriber sessions]
end
subgraph Privacy[Privacy & precision]
BLUR[Coarsen / blur]
OFF[Stop sharing]
AUDIT[Audit log]
end
subgraph Notif
PUSH((APNS / FCM))
GEOFENCE([Geofence trigger])
EMERG[SOS / emergency]
end
A --> LB --> WS --> ING --> GEO
GEO --> PUB --> SUB --> WS
ING --> HIST
Sharing --- A
Sharing --- B
Privacy --- ING
Privacy --- GEO
Notif --- GEOFENCE
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
class A,B client;
class WS edge;
class BATCH,REL,GRP,TEMP,SUB,BLUR,OFF,EMERG service;
class GEO,HIST,ACL datastore;
class PUB queue;
class ING,GEOFENCE compute;
class PUSH external;
class AUDIT obs;
Update cadence#
- High when moving fast / app in foreground; rare when stationary or background.
- Significant-location-change OS callback to save battery.
Privacy#
- Sharing is opt-in per friend, with temporary share windows.
- Coarsen precision for low-trust grants.
- Server stores last known location only by default; history is per-user opt-in.
Subscriber notification#
- Each user has a topic; subscribers receive deltas over WS.
- Geofence triggers: client-side or server-side rules (e.g., "notify me when X gets home").
Glossary & fundamentals#
Concepts referenced in this design. Each row links to its canonical page; the tag column shows whether it is a high-level (HLD) or low-level (LLD) concept.
| Tag | Concept | What it is | Page |
|---|---|---|---|
HLD |
Pub/Sub & message brokers | topics, consumer groups, delivery semantics | pub-sub-pattern |
HLD |
Observability | metrics, logs, traces, SLOs | observability |
HLD |
Realtime protocols | WS / SSE / polling / gRPC streaming | realtime-protocols |
LLD |
Async models | futures / async-await / coroutines / actors | async-models |
Quick reference#
Functional#
- Share live location with chosen friends/family.
- See last-known and live position on map.
- Geofence alerts.
- Temporary share links.
- Emergency SOS.
Non-functional#
- Update latency < 5 s glass-to-glass.
- Battery-efficient (sparse updates when idle).
- Strong privacy controls.
Capacity#
- 100M+ users; 100s of millions of small updates / hr.
- WS connections sized like chat (~100k per gateway).
Schema#
presence(user_id, lat, lng, accuracy, ts)Redis hash with TTLsharing(owner_id, viewer_id, since, until, precision)geofences(user_id, region, trigger_event)
Trade-offs#
- Always-on WS vs push wakeup: WS for foreground; push notifications wake app briefly.
- Per-user channel vs presence query: channel push is timelier; periodic query is simpler.
- Server-side history = nice UX but big storage/privacy risk; default off.
Refs#
- Apple Find My architecture talks (WWDC), Google Family Link / Maps share location, ByteByteGo "Design proximity / find friends".
FAQ#
How does Find My Friends share live location with low battery drain?#
Clients use significant change location updates and motion based triggers rather than constant GPS polling. Updates are batched and sent only when the user moves meaningfully or a watcher is active.
How does the system push location to watchers within 5 seconds?#
Watcher devices hold a WebSocket to a gateway. When a sharer publishes a new fix to a presence KV store, a fan out service pushes it to each subscribed watcher in real time.
How do geofence alerts work in Find My Friends?#
Each watcher defines named places. The location service runs a point in polygon check against the user's fences on every update and emits an arrived or left event when the boolean flips.
How is location privacy enforced?#
Sharing is explicit and opt in per recipient, with time bounded options like share for one hour. Server side ACLs are enforced on every location read so unsubscribed users see nothing.
How is the emergency SOS button implemented?#
SOS sends a high priority signal over the same gateway plus a fallback push. It surfaces last known location and battery to emergency contacts even if the device goes offline after.