CARTO started stamping "API KEY REQUIRED" across every keyless basemap tile on 26.08.2026. #2060 added a key field as the immediate answer, but it leaves a self-hosted instance needing an email exchange with CARTO before its maps look right, and every default in the client still pointed at CARTO. Default to OpenFreeMap Positron instead: no key, no account, no request limit, commercial use allowed, attribution required. OpenFreeMap serves vector tiles only, so the Leaflet basemap is a MapLibre style document rather than an XYZ template. maplibre-gl-leaflet hangs a GL canvas into Leaflet's own tile pane, which leaves everything above it alone - markers, GeoJSON, clusters, plugin layers, the custom panes, and the click handling, since Leaflet's CSS already puts pointer-events:none on that layer. maplibre-gl still arrives only through a dynamic import, so no chunk that draws a map grows by a megabyte. Switched: the trip planner, the MapView fallback every preview goes through, the journey map, collections, the atlas, the shared trip page and the offline tile prefetch. OpenFreeMap Positron and Bright join the tile presets in settings, the admin defaults and both mobile screens. A CARTO template that is already saved keeps working when a key backs it - that stays a supported choice. Without a key it is not drawn at all: resolveTileUrl falls back to the default rather than to a watermark, so an instance that upgrades with one in its settings sees the new basemap immediately and needs no migration. The stored value is left as it is, so the Map settings tab still shows what was chosen and the warning underneath it explains why - one sentence appended, in all 23 locales. OpenFreeMap asks for a credit of its own; OpenStreetMap alone under its tiles is wrong and a licence problem. attributionForTile() derives it from the URL rather than from a flag at each call site, and the shared trip map, which carried no attribution at all, now gets one. Offline maps keep working and get cheaper. A vector style is four things instead of one, so sync/glPrefetcher.ts walks the style document, its sprite, the Latin glyph ranges of each font stack it uses, the TileJSON - the planet path is versioned, so guessing it answers 200 with an empty body - and then the .pbf tiles. Over the Berlin bounding box TREK computes, raster z10-16 is 2237 requests and 34.6 MB and gives up above z16; vector z10-14 is 177 requests and 32.1 MB and stays sharp above that, because MapLibre scales the z14 tile rather than asking for another. The Workbox rule for tiles.openfreemap.org moves to CacheFirst and shares the prefetcher's cache, so browsing tops a downloaded region up instead of filling a second copy beside it - a versioned tile path can never be stale. Clearing offline maps clears it too. The atlas loses its second raster layer. It existed to warm the HTTP cache of neighbouring zoom levels, which a vector basemap does not need; a second one would only cost a second WebGL context. OpenFreeMap has no label-free style, so its labels are switched off on the live map instead - they are all symbol layers, while borders and coastlines are line and fill - re-armed on style.load so a theme switch keeps them off. Theme changes call setStyle in place rather than rebuilding the layer: a swap per toggle would leak a WebGL context, and browsers cap those in the low teens.
7.6 KiB
Offline Mode and PWA
TREK can be installed as a Progressive Web App (PWA) and used without an internet connection for previously synced trips.
Install as an app (PWA)
TREK must be served over HTTPS — the install prompt does not appear on plain HTTP.
iOS (Safari):
- Open TREK in Safari.
- Tap the Share button.
- Select Add to Home Screen.
Android (Chrome / Edge):
- Open TREK in the browser.
- Tap the browser menu.
- Select Install app or Add to Home Screen.
Once installed, TREK launches in standalone mode (fullscreen, no browser UI) using the TREK icon.
The installed app starts at the app root, so the Start page setting decides what you see when you tap the icon — the dashboard, or straight into your active trip on a tab of your choice. See Display-Settings.
What works offline
TREK uses Workbox service-worker caching plus an IndexedDB database (Dexie) for structured trip data. The following content is available offline after the first sync:
Service-worker cache (Workbox)
| Content | Cache name | Strategy | Duration | Max entries |
|---|---|---|---|---|
| Raster map tiles (OpenStreetMap, CartoDB, custom XYZ) | map-tiles |
CacheFirst | 30 days | 12 288 |
| Mapbox GL and OpenFreeMap style documents | gl-map-styles |
NetworkFirst (5 s timeout) | 30 days | 20 |
| Mapbox GL glyphs, sprites and vector tiles | mapbox-tiles |
StaleWhileRevalidate | 30 days | 3 000 |
| OpenFreeMap glyphs, sprites and vector tiles | gl-map-offline |
CacheFirst | 90 days | 6 000 |
Cover images and avatars (/uploads/covers, /uploads/avatars) |
user-uploads |
CacheFirst | 7 days | 300 |
| App shell and every page of the app (HTML / JS / CSS) | precache | Precached | Until next deploy | — |
Note: API responses are never stored in the service-worker cache. Workbox keys its entries by URL and cannot vary them on the session cookie, so on a shared device one account's cached data could be served to the next. Offline reads come from the per-user IndexedDB cache described below instead.
Note: The precache covers every page, not just the one you happen to open first. A page you have never visited still works after you lose connectivity — at the cost of a larger initial install.
IndexedDB (Dexie) — structured trip data
On login, when the browser comes back online, and when you lift Force offline mode, TREK runs a background sync that writes full trip bundles into IndexedDB — you can also start one by hand with Re-sync now, with Download for offline use for a progress-tracked run, or by re-enabling a trip's offline toggle:
- Trips, days, places, packing items, to-dos, budget items, reservations, accommodations, trip members, tags, and categories.
- File attachments that are neither photos nor videos (PDFs, documents, etc.) are downloaded and stored as blobs in IndexedDB. Videos are deliberately skipped — a single clip can be hundreds of megabytes and would evict the trip's real documents.
- Map tiles are pre-fetched into the service-worker
map-tilescache for zoom levels 10–16 across each trip's bounding box, stopping at the zoom level that would push the total past 12 288 tiles (roughly 180 MB).
Note: A WebSocket reconnect does not run this sync. It replays your queued changes and then re-reads the trip you currently have open — days, places, packing items, to-dos, budget items, reservations and files — which refreshes that one trip's cached rows. It never re-downloads the bundles for your other trips, the file blobs or the map tiles; skipping the full sync there is deliberate, so a dropped socket on an otherwise online device doesn't run into the server's rate limiter.
Sync scope and eviction
- Only ongoing and future trips are cached (trips whose
end_dateis today or later, or has no end date). - Trips that ended more than 7 days ago are automatically evicted from IndexedDB on the next sync.
Settings → Offline
The Offline tab gives you control over what is stored on this device and lets you go offline deliberately.
Offline mode
- Force offline mode — a switch that first downloads everything you need (see Prepare for offline below) and then routes the whole app to the local cache, queueing every change you make. Flip it back off to reconnect: queued changes are replayed and the cache is refreshed. The override is remembered across app restarts, so a session forced offline before a flight stays offline when the PWA relaunches.
- Prepare for offline → Download for offline use — a one-tap, progress-tracked download of trip data, documents and map tiles for every trip you keep offline. Unlike a background sync it waits for the downloads to finish, so the completion state means you really have everything.
- Re-sync now — refreshes the cache from the server. Disabled while offline.
What to store offline
- Store map tiles offline — map tiles use the most storage by far. Turn this off to keep only trip data and documents on the device; the pre-downloaded tile cache is cleared immediately.
- Per-trip toggle — each trip has its own on/off switch. Turning a trip off evicts its cached read data from the device (your unsynced edits are kept and still sync).
Sync conflicts
If a change you made offline collides with a newer change on the server, it is surfaced as a conflict instead of silently overwriting anything. The conflict list lets you keep mine or keep theirs per item. A default rule (Ask me each time / Always keep my version / Always keep the server version) is configurable under When a conflict happens. Conflict detection covers places and packing items.
Stats & cache
The stats panel shows cached trips, pending changes, conflicts and failed changes. Clear cache removes all offline data from IndexedDB (you can re-sync any time while online). Each cached trip entry shows its date range, place/file count and last successful sync.
Limitations
- Offline editing is supported for places and packing items (with conflict detection). Other entities — budget, to-dos, reservations, days — require connectivity to edit; while forced offline those edits still go to the live server when a connection is actually present.
- A change you made offline that deletes an item wins over a concurrent server edit of that same item ("delete wins"); only edit-vs-edit conflicts are surfaced for resolution.
- The conflict token has one-second resolution, so two edits to the same field within the same second can't be told apart and fall back to last-write-wins (only relevant to sub-second races; normal offline windows are unaffected).
- Creating a trip requires connectivity. Trip creation is not queued, so a new trip cannot be started while offline.
- Photo uploads require connectivity. Photo and video attachments are not pre-cached; every other file attachment is pre-cached automatically during sync.
- Real-time collaboration features require an active WebSocket connection.
- The Leaflet basemap is pre-downloaded, whether it is an OpenFreeMap vector style (style, sprite, glyphs and the vector tiles for the trip's area) or a raster template. Mapbox GL tiles are not pre-downloaded. With map-tile storage off, individually viewed tiles may still be cached opportunistically by the service worker.
