Building a Private GPS Tracker: Real-Time Location Tracking Without Google
I've got a Raspberry Pi sitting under my desk in Wigan that's been underutilised for months. I've also got six months of European travel ahead of me - Rome in April, Split in May, the UK over summer, Bratislava in September, then Gran Canaria and Tenerife through the end of the year. I wanted to track all of it. Not vaguely, not from memory, but precisely - every walk through a new city, every bus ride, every ferry crossing.
Google Timeline exists, obviously. But the data is Google's, not mine. It lives on their servers, processed by their algorithms, subject to their privacy policies. We're talking about my literal physical location here - where I sleep, where I eat, where I go. I wanted full ownership. So I built my own.
The Architecture
The system has four moving parts:
- My phone (Pixel 9 Pro) runs a GPS logging daemon inside Termux - a full Linux environment on Android. Every 5 minutes, it grabs a GPS fix and pushes the data over SSH.
- Tailscale connects everything. My phone, my Mac, my PC, and my Raspberry Pi all sit on the same private overlay network. No port forwarding, no dynamic DNS, no exposed services. Just encrypted peer-to-peer connections.
- The Raspberry Pi receives the GPS pings, stores them as daily JSON files, commits them to a local git repo, and serves a Leaflet map on port 8090.
- Authentication is Tailscale itself. Only devices on my network can reach the map. No accounts, no passwords, no external hosting.
That's it. Phone pings Pi. Pi stores and serves. Tailscale secures. The entire system runs on hardware I own, over a network only I control.
Getting GPS Right
The first GPS reading I got in Rome was 500 metres off. Not great when you're trying to track a walk through Trastevere. The issue was a stale cached position - the phone hadn't had time to acquire a proper satellite fix.
The fix was a warm-up routine. When the daemon starts, it takes an initial GPS reading and throws it away. It waits a few seconds for the satellites to settle, then takes the real reading. The difference was dramatic - my second reading was within 5 metres of where I was actually standing. Every reading since has been similarly accurate.
Cold GPS fixes are unreliable. Warm GPS fixes are remarkably precise. The daemon now handles this automatically on startup, and the accuracy has been consistently excellent.
Offline Queuing
Here's the thing about travelling - you're not always connected. Airplane mode on flights. Patchy signal on ferries. Dead zones in tunnels and rural areas. A GPS tracker that only works with connectivity isn't much of a tracker.
So the daemon logs locally regardless of network state. Every 5 minutes, it writes a GPS fix to a local queue on the phone. When connectivity returns, it flushes the entire backlog to the Pi in one go. This means I capture everything - including flight paths and ferry routes. When I flew into Rome, the daemon was logging the whole way. Those readings arrived at the Pi the moment I turned off airplane mode after landing.
This was one of those features that sounded like a nice-to-have but turned out to be essential. Some of the most interesting visualisations come from transit - seeing the arc of a flight path or the route of a ferry crossing between islands.
The Map
The frontend is a Leaflet map with a few layers that make the data come alive:
- Speed-coloured trails - walking shows in blue, running in green, transport in amber, driving in red. You can immediately see the character of a day at a glance. A day of exploring on foot is a web of blue lines. A day with a long bus ride is mostly amber with blue clusters at each end.
- Animated playback - you can scrub through a day's movement like a time-lapse, with play/pause and speed controls. Watching a dot trace your own path through a city you explored that morning is genuinely mesmerising.
- Heatmap layer - shows frequently visited areas as heat zones. After a few weeks in a city, your routine becomes visible. The apartment glows. The local coffee shop glows. The route between them is a warm line.
Fitbit Integration
Location data alone tells you where you went. But I also wanted to know how the day felt. A daily cron job runs at noon and pulls my Fitbit stats via the Fitbit Web API - steps, heart rate, and sleep data. These show up in a stats panel alongside the map.
The combination is surprisingly powerful. I can look at a day where I walked 25,000 steps and see the exact route overlaid with my heart rate data. Big exploration days light up on both the map and the health stats. Rest days are obvious too - a small cluster of blue around the apartment with a low step count.
I'd actually built a Fitbit MCP project previously that gave me a good understanding of the Fitbit Web API, so wiring this up was straightforward. Past projects paying dividends.
Monitoring
The daemon is designed to be invisible - it runs in the background and I shouldn't have to think about it. But if something goes wrong, I want to know. If the Pi hasn't received a GPS ping in 30 minutes, it sends me a push notification via ntfy. Simple, effective, and it's already caught a couple of cases where Termux got killed by Android's battery optimisation. A quick restart and the backlog flushes through.
Built in an Evening
Here's the part that still surprises me. The entire system - phone daemon, Pi backend, Leaflet frontend, Fitbit integration, offline queuing, monitoring - was built and deployed in a single evening session.
I didn't write any code. I used Claude Code in Team Lead Mode, orchestrating multiple AI agents working in parallel. One agent wrote the GPS daemon and phone-side scripts. Another built the map frontend. Another configured the Pi's storage and git automation. Another set up the Fitbit cron and ntfy alerts. I made architectural decisions and directed the work while the agents implemented.
The whole thing started from an idle thought - "what else can I do now that I can SSH into my phone?" - and three hours later I was watching a real-time dot trace my position on a private map in Rome. The speed of going from idea to deployed system is something I'm still getting used to with AI-first development. It changes what's worth building. Projects that would have taken a weekend and therefore might not happen at all now take an evening and therefore do.
The Payoff
The first time I opened the map on my phone and saw my own dot moving through Rome in real time, on my own infrastructure, with my own data - I was genuinely blown away. It sounds simple, but there's something deeply satisfying about a system you built yourself showing you exactly where you are in the world.
I'm most excited about what this will look like at the end of six months. Every city I visit, every route I take, every flight and ferry - all captured, all mine. I'll be able to play back my entire European journey as an animation. Walking through Rome in April. Exploring Split in May. The ferry from Gran Canaria to Tenerife. All of it, rendered as trails on a map with my health data alongside.
For someone who loves reminiscing about travel, having precise, visual, self-hosted records of everywhere I've been is the kind of thing I didn't know I wanted until I had it. And the fact that none of this data touches a corporate server - that it lives on a Raspberry Pi under my desk - makes it feel like it's actually mine in a way that Google Timeline never could.