Alle Artikel
/ 5 Min. Lesezeit

LiveTrecker: Echtzeit-GPS-Tracking für einen 109-km-Spendenlauf

Wie ich eine Fullstack-App mit React Native, Socket.io und Leaflet gebaut habe, um einen 109-km-Spendenlauf live zu tracken.

React NativeSocket.ioGPS-TrackingGarmin APIMapboxNode.js
suetti.it/dev-log
LiveTrecker: Echtzeit-GPS-Tracking für einen 109-km-Spendenlauf

Mein Bruder Erik wollte 109 Kilometer am Stück laufen — den kompletten Wasserweltensteig von Triberg im Schwarzwald bis zum Rheinfall bei Schaffhausen. An einem Tag. Nicht für sich, sondern um Spenden für das Kinderhilfswerk Compassion zu sammeln. Zusammen mit einem Kumpel wollte ich ihn begleiten — ich auf dem Gravelbike, er auf dem Mountainbike — und Interessierten die Möglichkeit geben, das Event live zu verfolgen. Also habe ich LiveTrecker gebaut.

Und ja — "LiveTrecker" ist kein Rechtschreibfehler. Der Name ist eine Anspielung auf den Trecker (Bulldog, Traktor).

Der Anlass: Muskathlon@Home 2021

Am 12. Juni 2021 machten sich im Rahmen des Muskathlon@Home in ganz Deutschland hunderte Läufer, Biker und Wanderer auf den Weg, um mit ihrem Einsatz die Arbeit von Compassion auf den Philippinen zu unterstützen. Erik hatte sich den Wasserweltensteig ausgesucht — 109 km, rund 2.200 Höhenmeter, Start um 04:00 Uhr morgens.

Streckenkarte Wasserweltensteig
Streckenkarte Wasserweltensteig

Ich hatte mich in der Vorbereitung leider verletzt und konnte nicht mitlaufen. Stattdessen habe ich Erik auf dem Gravelbike begleitet, zusammen mit unserem Kumpel auf dem MTB — und genau dafür die Tracking-Plattform gebaut: Eine Fullstack-Lösung, mit der Freunde, Familie und Spender den Lauf in Echtzeit auf einer Karte verfolgen konnten. Am Ende kamen über 4.000 € an Spendengeldern zusammen.

Muskathlon@Home — Einsatz gegen extreme Armut
Muskathlon@Home — Einsatz gegen extreme Armut

Phase 1: LiveTrecker — der React-Native-Prototyp

Der erste Ansatz war eine komplett selbst gebaute Tracking-App mit React Native. Die Idee: GPS-Positionen im Hintergrund erfassen, per Socket.io an einen Node.js-Server senden und auf einer Leaflet-Karte live anzeigen.

Die App bestand aus drei Teilen:

  • Mobile App (React Native): Background-GPS mit @mauron85/react-native-background-geolocation
  • GPS-Server (Node.js + Socket.io): Empfängt Positionsdaten und broadcastet per WebSocket
  • WebApp (React + Leaflet): Live-Karte mit animiertem Läufer-Marker
BackgroundGeolocation.configure({
  desiredAccuracy: BackgroundGeolocation.HIGH_ACCURACY,
  stationaryRadius: 50,
  distanceFilter: 20,
  activityType: 'Fitness',
  stopOnTerminate: true
});

Jede Position wurde lokal im AsyncStorage gepuffert und gebündelt an den Server gesynct — Offline-First, damit im Schwarzwald keine Daten verloren gehen. Die Track-ID wurde per Bit-Shifting aus GPS-Position und Timestamp direkt auf dem Gerät generiert, ohne Server-Roundtrip.

Der Prototyp funktionierte, hatte aber Grenzen: Die React-Native-App brauchte ein Smartphone oder Android-Gerät, die Leaflet-Karte war zweidimensional, und es gab keinen Chat. Für das eigentliche Event brauchte ich mehr.

Phase 2: GarminLiveTrack — die Live-Plattform

Für den Event-Tag habe ich eine komplett neue Tracking-Plattform gebaut: GarminLiveTrack. Statt eigener GPS-Erfassung nutzt sie die Garmin LiveTrack API — Eriks Garmin-Uhr streamte die GPS-Daten, und mein Backend pollte sie in Echtzeit.

Garmin LiveTrack Backend

Das Backend pollt die GPS-Daten direkt von den Tracking-APIs der jeweiligen Geräte:

// Garmin LiveTrack API
$tpUrl = "https://livetrack.garmin.com/services/session/{$session}/trackpoints";
$json = json_decode(file_get_contents($tpUrl));

foreach ($json->trackPoints as $tp) {
    // Latitude, Longitude, Altitude, Distanz, Dauer
    $sql = "INSERT IGNORE INTO garmin_trackpoints
            (session_id, lat, lng, alt, meter, sek)
            VALUES (?, ?, ?, ?, ?, ?)";
}

Die Daten von Eriks Garmin-Uhr landeten in einer MySQL-Datenbank. Ein Cron-Job pollte die Garmin LiveTrack API alle paar Sekunden und schrieb neue Trackpoints in die DB. Duplikate wurden per INSERT IGNORE und gehashter Track-Point-ID verhindert.

Mapbox-Karte mit 3D-Terrain

Statt der flachen Leaflet-Karte kam jetzt Mapbox GL zum Einsatz — mit WebGL-Rendering und 3D-Terrain:

// Maptrack.js — Alle 5 Sekunden neue Daten abrufen
fetch(\`/api/track/\${trackID}/\${lastid}\`)
  .then(resp => resp.json())
  .then(json => {
    this.route(true);       // Strecke aktualisieren
    this.statistik();       // Pace, Distanz, Zeit
    this.fitMap(lat, lng);  // Karte auf Läufer zentrieren
  });

Die Karte zeigte die Strecke als animierte Linie auf einer detaillierten Outdoor-Karte — mit Höhenprofil, Echtzeit-Statistiken (Pace, Distanz, Zeit) und einem Live-Spendenstand, der direkt von der Compassion-Plattform abgerufen wurde.

Erik auf dem Wasserweltensteig — Pause mit Aussicht
Erik auf dem Wasserweltensteig — Pause mit Aussicht

Live-Chat und Medien-Upload

Das Highlight der Plattform: Ein integrierter Live-Chat. Zuschauer konnten Nachrichten schicken, Fotos und Videos hochladen — alles in Echtzeit. Auf der Strecke konnte ich die Nachrichten auf dem iPhone lesen und antworten, während Erik lief und wir auf den Bikes hinterherfuhren.

Die Fotos der Zuschauer und unsere eigenen Aufnahmen von unterwegs erschienen direkt im Chat-Feed. Video-Uploads wurden serverseitig mit einem Poster-Frame versehen. Ein Besucherzähler zeigte an, wie viele Leute gerade live dabei waren.

Zusätzlich war eine Twilio-Integration eingebaut: Nachrichten konnten auch per SMS oder WhatsApp an den Läufer geschickt werden.

Erik und Thomas auf dem Waldweg — live getrackt
Erik und Thomas auf dem Waldweg — live getrackt

Das Setup am Event-Tag

Start 04:00 Uhr morgens in Triberg. Erik mit Garmin-Uhr am Handgelenk, ich auf dem Gravelbike und unser Kumpel auf dem MTB. Die Garmin-Uhr streamte die GPS-Daten live an unser Backend.

Die Spendenseite auf muskathlon.suetti.it hatte einen Countdown, der um 04:00 Uhr automatisch auf die Live-Karte umschaltete. Eingebettet per iFrame direkt von livetrack.suetti.it.

Erik füllt an einer Quelle auf dem Wasserweltensteig Wasser nach
Erik füllt an einer Quelle auf dem Wasserweltensteig Wasser nach

Der Weg war nicht immer einfach — der Wasserweltensteig führt durch enge Schluchten und über schlammige Waldwege. Mit den Bikes mussten wir an manchen Stellen schieben.

Mit dem Bike durch den Schlamm — der Wasserweltensteig war nicht immer fahrbar
Mit dem Bike durch den Schlamm — der Wasserweltensteig war nicht immer fahrbar

Learnings

  • API statt eigener GPS-Erfassung: Die Garmin LiveTrack API liefert zuverlässigere Daten als eine selbst gebaute App. Die React-Native-App war ein guter Prototyp, aber für ein echtes Event ist die API-Integration robuster
  • Chat macht den Unterschied: Ohne den Live-Chat wäre es nur eine Karte mit einem Punkt gewesen. Die Interaktion mit den Zuschauern hat das Event lebendig gemacht und die Spendenbereitschaft deutlich gesteigert
  • Offline-First bleibt wichtig: Im Schwarzwald gibt es Funklöcher ohne Ende. Das lokale Buffering aus dem LiveTrecker-Prototyp hat sich als Konzept bewährt

Verwandte Projekte

Wenn dich GPS und Laufen interessiert: In meinem Laufband-Steuerungsprojekt nutze ich GPX-Tracks, um die Steigung eines NordicTrack-Laufbands per Raspberry Pi zu steuern — das Indoor-Gegenstück zu LiveTrecker.

TS

Timo Sütterlin

Fullstack-Entwickler — Web, Mobile, KI

Weitere Artikel

← Alle Artikel