Nearby Friends shows you that a friend is “0.3 miles away.” It does not show you their exact coordinates. This is not just a UI choice: the system should never expose precise location data even if the client asks for it. Privacy-aware proximity means computing distance and revealing enough for the feature to be useful, while structurally preventing exact location exposure.

Bucketed Distance#

The simplest approach: compute exact distance server-side, then bucket the result before returning it. Instead of “0.31 miles,” return “less than half a mile.” The buckets: under 0.1 miles, 0.1-0.5 miles, 0.5-1 mile, 1-2 miles, 2-5 miles, over 5 miles.

The client receives a bucket, never a coordinate. Even if someone intercepts the API response, they get a range. Over time, watching bucket transitions gives some information about direction of movement, but it’s much harder to triangulate than exact coordinates.

Geohash Grid Fuzzing#

A stronger approach: store each user’s location as a geohash at reduced precision. Geohashing at precision 5 gives a cell roughly 5km x 5km. Store the cell center, not the user’s actual position. Users within the same cell appear at identical coordinates. Users in adjacent cells can be compared at cell-center distance.

This adds up to 3km of error in the worst case (user is at cell edge). That’s acceptable for “nearby friends” but not for navigation. The privacy gain: you can’t pinpoint someone to better than 2.5km in any direction.

graph TD A[User at 37.7749 lat, -122.4194 lon] --> B[Geohash at precision 5: 9q8yy] B --> C[Store cell center: 37.773 lat, -122.418 lon] C --> D[Nearby query: compare cell centers] D --> E[Return bucketed distance: within 1 mile] E --> F[Client never sees real coordinates] style A fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style B fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style C fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style D fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style E fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style F fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff

Location sharing should be bilateral: you see a friend’s location only if they have opted in to sharing with you. Store visibility as a directed edge in the social graph: user A shares with user B does not imply B shares with A. Query: “who is near me?” returns only friends where both the sharing edge A→B and B→A exist.

This prevents a stalking scenario: someone who hasn’t opted in to sharing cannot see others, and cannot be seen without consent.

Time Fuzzing#

Add random delay of 1-5 minutes to location updates before storing. A watcher observing location bucket changes over time cannot accurately determine speed or direction of movement. The cost: “nearby” could mean nearby 5 minutes ago.

At Salesforce#

We built an org proximity feature for Salesforce maps: showing customer sites near a sales rep’s current location. We never stored the rep’s exact GPS coordinates. We stored the nearest metropolitan area centroid (city-level precision). Reps within 50km of a customer site were flagged. This was accurate enough for scheduling decisions and ensured no rep’s precise movements were logged in our systems.

What I’m Learning#

Privacy-aware proximity is about building privacy in structurally, not just as a UI filter. If the backend computes exact distances and the API only returns buckets, a motivated attacker can still call the API repeatedly and triangulate. Storing fuzzed coordinates from the start prevents that class of attack.

Have you designed systems where location privacy was a hard requirement, and how did you solve it?