Geolocation API Implementation on Website
Geolocation API gives device coordinates via GPS, WiFi triangulation, or IP geolocation. Browser always requests user permission. Accuracy ranges from meters (GPS outdoors) to kilometers (IP).
Get Current Position
interface GeoPosition {
lat: number
lng: number
accuracy: number // meters
altitude?: number
speed?: number // m/s
heading?: number // degrees from north
timestamp: number
}
async function getCurrentPosition(
options: PositionOptions = {}
): Promise<GeoPosition> {
if (!navigator.geolocation) {
throw new Error('Geolocation API not supported')
}
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
(position) => {
resolve({
lat: position.coords.latitude,
lng: position.coords.longitude,
accuracy: position.coords.accuracy,
altitude: position.coords.altitude ?? undefined,
speed: position.coords.speed ?? undefined,
heading: position.coords.heading ?? undefined,
timestamp: position.timestamp,
})
},
(error) => reject(mapGeolocationError(error)),
{
enableHighAccuracy: options.enableHighAccuracy ?? false,
timeout: options.timeout ?? 10000,
maximumAge: options.maximumAge ?? 0,
}
)
})
}
function mapGeolocationError(error: GeolocationPositionError): Error {
const messages: Record<number, string> = {
1: 'User denied geolocation access',
2: 'Position unavailable (no signal)',
3: 'Position request timeout exceeded',
}
return new Error(messages[error.code] ?? 'Unknown geolocation error')
}
Watch Position
For route tracking, navigation, or live map updates:
class GeolocationWatcher {
private watchId: number | null = null
private onPosition: (pos: GeoPosition) => void
private onError: (err: Error) => void
constructor(
onPosition: (pos: GeoPosition) => void,
onError: (err: Error) => void
) {
this.onPosition = onPosition
this.onError = onError
}
start(highAccuracy = true): void {
if (this.watchId !== null) return
this.watchId = navigator.geolocation.watchPosition(
(position) => {
this.onPosition({
lat: position.coords.latitude,
lng: position.coords.longitude,
accuracy: position.coords.accuracy,
speed: position.coords.speed ?? undefined,
heading: position.coords.heading ?? undefined,
timestamp: position.timestamp,
})
},
(error) => this.onError(mapGeolocationError(error)),
{ enableHighAccuracy: highAccuracy, timeout: 5000, maximumAge: 1000 }
)
}
stop(): void {
if (this.watchId !== null) {
navigator.geolocation.clearWatch(this.watchId)
this.watchId = null
}
}
}
React Hook
interface UseGeolocationReturn {
position: GeoPosition | null
error: string | null
loading: boolean
get: () => Promise<void>
watch: () => void
stopWatch: () => void
}
function useGeolocation(): UseGeolocationReturn {
const [position, setPosition] = useState<GeoPosition | null>(null)
const [error, setError] = useState<string | null>(null)
const [loading, setLoading] = useState(false)
const watcherRef = useRef<GeolocationWatcher>()
useEffect(() => {
watcherRef.current = new GeolocationWatcher(
(pos) => setPosition(pos),
(err) => setError(err.message)
)
return () => watcherRef.current?.stop()
}, [])
const get = useCallback(async () => {
setLoading(true)
setError(null)
try {
const pos = await getCurrentPosition({ enableHighAccuracy: true })
setPosition(pos)
} catch (e) {
setError(e instanceof Error ? e.message : 'Geolocation error')
} finally {
setLoading(false)
}
}, [])
const watch = useCallback(() => watcherRef.current?.start(), [])
const stopWatch = useCallback(() => watcherRef.current?.stop(), [])
return { position, error, loading, get, watch, stopWatch }
}
Distance Calculation (Haversine Formula)
Often needed with geolocation — find nearest objects, show distance:
function haversineDistance(
a: { lat: number; lng: number },
b: { lat: number; lng: number }
): number {
const R = 6371000 // Earth radius in meters
const toRad = (deg: number) => (deg * Math.PI) / 180
const dLat = toRad(b.lat - a.lat)
const dLng = toRad(b.lng - a.lng)
const ha =
Math.sin(dLat / 2) ** 2 +
Math.cos(toRad(a.lat)) * Math.cos(toRad(b.lat)) * Math.sin(dLng / 2) ** 2
return R * 2 * Math.atan2(Math.sqrt(ha), Math.sqrt(1 - ha))
}
// Find nearest object
function findNearest<T extends { lat: number; lng: number }>(
current: { lat: number; lng: number },
points: T[]
): T | null {
if (!points.length) return null
return points.reduce((nearest, point) =>
haversineDistance(current, point) < haversineDistance(current, nearest)
? point
: nearest
)
}
What's Involved
Utilities for getting and watching position, proper error handling (denial, timeout, unavailability), React hook, distance calculations, integration with map (Leaflet, Google Maps, Mapbox) if needed.
Timeline: 0.5–1 day. With map — 1–2 days.







