Py_RouteTracker is a self-hosted telemetry overlay studio for action-cam footage.

The app name in the UI is PitLane, and the job is clear: drop in a video, extract telemetry, choose HUD widgets, render the overlay, and download the finished clip.

The part that makes it worth writing about is where the work happens.

Py_RouteTracker runs trimming, joining, telemetry extraction, lap detection, HUD drawing, compositing, and rendering in the browser.

What is Py_RouteTracker?

Py_RouteTracker, or PitLane, is an AGPL-3.0 web app for overlaying GPS and G-force telemetry onto action-cam videos.

It supports two telemetry paths:

  • GoPro embedded GPS/GPMF telemetry from the video file.
  • A separate GPX track synced to the video.

It can also join split action-cam recordings before extraction. That matters for GoPro-style chaptered recordings, where one long session becomes multiple MP4 parts.

Why Self-Host It?

Self-host Py_RouteTracker if you want private telemetry overlays without uploading raw footage to a SaaS video tool.

Good use cases:

  • GoPro road trips, track days, cycling, karting, drone or action-cam footage;
  • GPS speed overlays;
  • lap timing and lap-vs-lap visual comparison;
  • G-force display when acceleration data is available;
  • browser-side rendering from a local machine;
  • a private PWA install on a laptop or tablet.

The backend does not process your footage. In the current architecture it only serves the built web app.

Tech Overview

I inspected commit:

b7eb9d2d06cdf84af429faf81dae61241fc31fee

There was no GitHub release object at analysis time, so the Docker snippet pins the short-SHA image:

ghcr.io/jlleongarcia/py_routetracker:b7eb9d2

The stack:

  • Frontend: React 19, TypeScript, Vite 8.
  • PWA: vite-plugin-pwa with Workbox-generated service worker.
  • Backend: FastAPI static-file server.
  • Media pipeline: mediabunny.
  • MP4 handling: mp4box.js and mediabunny.
  • Telemetry: gpmf-extract, gopro-telemetry, custom GPX parser.
  • Rendering: WebCodecs, OffscreenCanvas/Canvas2D, workers.
  • HEVC fallback: @yume-chan/libde265 WebAssembly decoder.
  • Container: Python 3.12 slim runtime serving built frontend on port 7000.

Is the PWA Real?

Yes.

The frontend uses vite-plugin-pwa, not a hand-written placeholder manifest.

The Vite config sets:

  • registerType: "prompt";
  • injectRegister: false;
  • Workbox precache patterns for js, css, html, ico, png, svg, and wasm;
  • manifest display: "standalone";
  • manifest start_url: "/";
  • manifest scope: "/";
  • PWA icons including maskable icon support.

The app also has:

  • InstallPrompt.tsx, which captures beforeinstallprompt and handles iOS Add to Home Screen guidance.
  • UpdateToast.tsx, which shows update and offline-ready messages through virtual:pwa-register/react.

I also checked the built container output. It served:

  • /manifest.webmanifest;
  • /sw.js;
  • index.html;
  • worker bundles;
  • assets/libde265-*.wasm;
  • app icons.

The service worker precache included 19 entries, including the WASM HEVC decoder asset.

Can It Be Deployed Statically?

Yes, the frontend can be deployed as a static app.

The backend exists mainly so the Docker image can serve the built frontend through FastAPI/Uvicorn and expose /api/health.

For Cloudflare Pages, the likely setup is:

Root directory: frontend
Build command: npm ci && npm run build
Build output directory: dist
Node version: 22

That should provide the web UI, PWA manifest, service worker, Workbox runtime, browser workers, and WASM assets.

The important condition is HTTPS. Rendering depends on WebCodecs, and browsers expose WebCodecs only in a secure context. http://localhost and http://127.0.0.1 are special-cased and work locally, but plain HTTP on a LAN IP, normal hostname, or Tailscale IP will break rendering.

Cloudflare Pages gives you HTTPS, so it is a reasonable static deployment target.

Does Static Hosting Give Full Functionality?

For the core app, yes.

The heavy workflow is browser-side:

  • upload stays local;
  • split recordings can be joined locally;
  • GoPro GPMF telemetry is read in the browser;
  • GPX files are parsed in the browser;
  • lap detection runs in the browser;
  • the HUD is drawn in the browser;
  • final video rendering runs in a worker.

But “full functionality” still depends on browser capabilities:

  • WebCodecs must exist.
  • The browser must decode/encode the needed codecs.
  • Official Chrome or Edge is a safer choice than some Linux distro Chromium builds for H.264/AAC.
  • HEVC can fall back to the WASM libde265 decoder, but encoding still needs WebCodecs.
  • File System Access streaming is Chromium-only; other browsers can fall back to a Blob download path.
  • The map preview uses OpenStreetMap tiles, so the map background is not fully offline unless tile data is already cached.

So yes, it can be static and still be the real app. It is not just a demo shell. The browser is the runtime.

Self-Hosting with Docker

The easiest self-host path is Docker.

The reusable Home-Lab compose file is here:

The site can include the same snippet from the Home-Lab submodule:

assets/snippets/py-routetracker/docker-compose.yml
includeyaml: file not found or not allowed by security.filesystem.allow: assets/snippets/py-routetracker/docker-compose.yml

Create .env from the sample:

cp assets/snippets/py-routetracker/.env.sample assets/snippets/py-routetracker/.env

Start it:

cd assets/snippets/py-routetracker
docker compose up -d

Open it locally:

http://localhost:7000

Check health:

curl http://localhost:7000/api/health

If you want to access it from another device, use HTTPS. Tailscale Serve, Cloudflare Tunnel with Access, Caddy, Traefik, or another TLS path is the practical answer.

Do not assume http://192.168.x.x:7000 will render videos correctly. It can load the page, but rendering can fail because WebCodecs is unavailable in an insecure context.

Field Test

I tested the pinned image:

docker run -d --name pyroutetracker-foss-trial \
  -p 127.0.0.1:17000:7000 \
  ghcr.io/jlleongarcia/py_routetracker:b7eb9d2

Results:

  • /api/health returned {"status":"ok"}.
  • / returned 200 OK with frontend HTML.
  • /manifest.webmanifest returned the PWA manifest.
  • /sw.js returned the Workbox service worker.
  • The image labels pointed back to commit b7eb9d2d06cdf84af429faf81dae61241fc31fee.
  • The image manifest supports linux/amd64 and linux/arm64.
  • The test container was removed afterward.

I also ran the backend tests:

1 passed, 1 skipped, 1 warning

The frontend failed on the host’s Node 18 because the toolchain expects newer Node APIs. Re-running in node:22-slim passed:

13 test files passed
102 tests passed
PWA generated dist/sw.js and dist/workbox-*.js
Precache: 19 entries, 2660.14 KiB

Browser and Codec Caveats

The main caveat is not the server. It is the browser.

Rendering needs WebCodecs. If WebCodecs is unavailable, the app can still upload, trim, and extract telemetry, but final video rendering fails.

H.264 and AAC are common in action-cam footage. Some Linux Chromium builds lack the licensed codec support needed to decode them through WebCodecs, even when the WebCodecs API exists. The project explicitly recommends official Chrome or Edge for that situation.

HEVC is handled better than I expected. If the browser cannot decode HEVC natively, the app can register a WASM libde265 decoder and continue. It will be slower, especially for 4K, but it avoids a hard stop for newer GoPro footage.

Rendered output is 8-bit SDR because the compositing path goes through Canvas2D.

Cloudflare Notes

For Cloudflare Pages, deploy the static frontend.

For Cloudflare Tunnel in front of the Docker container, the README calls out two important settings:

  • turn Rocket Loader off;
  • bypass cache for /sw.js.

That second point is important for PWAs. A stale cached service worker can keep users stuck on an old build.

When to Pick Py_RouteTracker

Pick it if you want telemetry overlays without running a video processing backend.

It is a strong fit for a homelab or personal workflow where footage stays on the same device doing the render. The PWA model also makes sense: install it, load it once, and keep a local tool available.

Skip it if you want a server-side render farm, collaborative project storage, account-based media management, or guaranteed support for every browser and codec combination.

Final Thoughts

Py_RouteTracker is more impressive than the name suggests.

It is not a Python video backend with a web skin anymore. It is a React/Vite PWA where the browser is the media workstation, and the Python part is just a thin static-file server for the Docker path.

For self-hosters, that is a useful shape: simple to run, private by design, and surprisingly capable when opened in a modern Chromium browser over HTTPS.