I recently worked on a location tracking feature that was causing major problems. The app would drain phone batteries quickly, the server costs were getting expensive, and users were complaining about lag. Here's how I fixed it.
π΄ What Was Wrong
The system had some serious issues:
- Phones were losing 20-30% battery every hour
- The app was sending way too many updates through Socket.IO
- The database was handling thousands of writes every minute
- Server costs kept increasing as more people used the app
- The map would freeze and lag when updating locations
π Why These Problems Happened
After checking the logs and monitoring the system, I found the main causes:
- The app was sending location updates every single second via Socket.IO
- Every time someone moved, the server sent everyone's locations to all users
- Every location update was being saved to the database immediately
- GPS was set to maximum accuracy all the time
- There was no caching system to handle the load
β‘ How I Fixed It
1. Sending Only What Changed and Filtering Insignificant Movements
This was the biggest improvement. Instead of the previous approach, I implemented two key changes:
Client-side filtering: The phone only sends location updates when movement exceeds 10 meters, eliminating unnecessary network calls
Selective broadcasting: The server broadcasts only the changed user's location instead of sending everyone's data to all users
Result: Socket.IO traffic went down by 60% and made everything much faster.
2. Adding a Caching System
I set up Redis to handle the constant location updates:
The caching strategy:
- The server stores the latest location in Redis with a 2-minute TTL to remove stale data
- A background job saves active user's locations to the main database every 60 seconds
- When a user stops tracking, their final location is immediately saved to the database before marking them inactive. This ensures we never lose the end point of a journey
- Start/stop events instantly update the active-users list in Redis so the map doesn't show inactive devices
Result: Database writes reduced by 90% and saved a lot on server costs.
3. Better GPS Settings
I changed how the phone's GPS works:
Key changes:
- Use balanced accuracy instead of maximum (saves battery)
- Send updates only when movement exceeds 10 meters (reduces network usage and battery drain)
- Background updates use OS-recommended minimum intervals to reduce battery drain further
Result: Battery life improved by 60%.
4. Fixing the Map Display
The map re-rendering was optimised by updating only affected markers and memoising static elements.
Key optimizations:
- Only update markers for users whose locations actually changed
- Memoize static map elements to prevent unnecessary re-renders
Result: The map stayed smooth with no lag, even with many active users.
π The Results
After all these changes, the improvements were significant:
| Metric | Improvement |
|---|---|
| Battery life | 60-70% better |
| Socket.IO traffic | 60% reduction |
| Database writes | 90% reduction |
| Server costs | 50% reduction |
| Map performance | No lag |
| Data integrity | Zero data loss |
π‘ What I Learned
Real-time doesn't mean every second: Most apps don't need constant updates. Sending data only when the user has moved a meaningful distance (10+ meters) saves battery and network resources.
Only sending what changed: Broadcasting only the updated user's location instead of everyone's data was a game-changer for network efficiency.
Use caching wisely: Redis helped handle the constant flow of updates without overloading the database.
GPS accuracy costs battery: High accuracy mode drains battery really fast. Balanced mode works great for most cases and users can't tell the difference.
Handle stop events properly: Immediately saving the final location when users stop tracking prevents data loss and ensures complete trip records.
Filter on the client when possible: Processing location changes on the phone before sending them to the server reduces network traffic and server load.
π How It All Works Now
Here's the complete flow:
βββββββββββββββββββ
β User starts β
β tracking β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ
β Phone GPS with β
β balanced mode β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ
β Filter: Only β
β send if moved β
β 10+ meters β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ
β Server stores β
β in Redis β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ
β Broadcast only β
β changed user β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ
β Background job β
β saves to DB β
β every 60s β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ
β User stops: β
β Immediate save β
β to database β
βββββββββββββββββββ
Detailed steps:
- User starts tracking: Phone GPS begins collecting location with balanced accuracy mode
- Location filtering: Phone only sends updates to server when movement exceeds 10 meters
- Server processing: Server stores the latest location in Redis and immediately broadcasts only the changed user's data via Socket.IO
- Periodic saves: Background job runs every 60 seconds, saving all active users' locations from Redis to the database
-
User stops tracking: Server immediately saves the final location to database with
active=false, removes user from active list in Redis, and broadcasts stop event to other users - New user joins: When a user opens the app, the server fetches all current active locations from Redis and sends them once as an initial payload
π― Final Thoughts
Fixing location tracking isn't about finding one magic solutionβit's about making thoughtful decisions at each layer of the system. From GPS collection to network transmission to database storage, small improvements compound into significant gains.
I learned that handling edge cases (like user stops and starts) and filtering unnecessary updates early in the pipeline can prevent much bigger problems downstream.
These optimizations helped turn a problematic feature into something more reliable and cost-effective, though there's always room to learn and improve further. Every system has its unique constraints, and what worked here might need adjustment for different use cases.
Top comments (0)