The problem
I kept wanting to know my exact altitude while hiking. Every option I found was either a bloated native app full of ads and permissions I didn't need, or a website that made me create an account before showing me a single number.
So I built Zirvə — open it, allow location once, get your elevation above sea level in seconds. No install, no account, no ads.
This post is about the two technical decisions that mattered most: how altitude is actually measured, and what happens when there's no signal.
Altitude is harder than it looks
The obvious approach is navigator.geolocation and reading coords.altitude. It works — sometimes. Phone GPS chips measure vertical position much less accurately than horizontal position (think ±10–30m, versus a few meters for lat/lng), and plenty of devices — most desktops, some older phones — return null for altitude entirely.
The fix was to treat GPS altitude as a fallback, not the primary source. The primary source is a terrain elevation API (Open-Meteo), which returns the elevation of your exact coordinates from a real digital elevation model — accurate to about 1–3 meters, regardless of what your device's GPS chip can do.
async function fetchElevation(lat, lon){
try {
const res = await fetch(elevationApiUrl(lat, lon));
const data = await res.json();
applyElevation(Math.round(data.elevation[0]));
} catch(e) {
// fall back to GPS altitude below
}
}
What happens with no signal
This is the part that actually mattered for the use case. A hiker above the treeline, with no signal, still wants a number.
If the terrain API call fails — timeout, offline, whatever — the app falls back to the raw altitude from the GPS fix that already ran. Locating requests lat, lng and altitude together, so there is no extra permission prompt and no extra round trip. If that is also unavailable, it shows nothing rather than a stale or fabricated number. A wrong altitude is worse than no altitude.
catch(e){
if(gpsAltitude === null){
// device has no altitude data offline — say so, don't guess
return;
}
applyElevation(gpsAltitude);
markApproximate(); // UI shows "offline — approximate"
}
The UI marks the reading as approximate whenever it is GPS-sourced, so nobody mistakes ±20m for the API's ±2m.
Why PWA instead of a native app
Zero install friction was the actual product requirement — someone finding this mid-hike shouldn't need an app store, a download, or a permission dialog beyond location. A service worker with a network-first strategy handles the rest: fresh code when there's a connection, cached shell when there isn't.
self.addEventListener('fetch', e => {
e.respondWith(
fetch(e.request)
.then(res => cacheAndReturn(res))
.catch(() => caches.match(e.request))
);
});
What's next
Right now it's a solo project I maintain in whatever time I have outside work. Next up: a proper elevation profile for the current session's track, and looking at whether a barometric-pressure fallback (where the device exposes it) could tighten the offline accuracy further.
If you hike, climb, or just like knowing exactly how high you're standing — try it. Free, no ads, no sign-up. Feedback welcome, especially from anyone who's hit the offline fallback path for real.
Top comments (0)