Activity Explorer is a local, open-source Blazor application for exploring your cycling, running, and walking history. It works from files you own - Garmin account exports, Strava bulk exports, and individual FIT, GPX, TCX, GZ, or ZIP files - without API credentials, web scraping, or automated access to Garmin or Strava.
Version 0.1.0 is deliberately local-first and has no login system. It binds to localhost by default and stores the database, imported originals, and logs outside the repository.
- Imports official Garmin and Strava account exports and individual activity files.
- Provides official-history ZIP, bounded multi-file, and local-inbox workflows without accepting provider credentials.
- Keeps immutable copies of every distinct imported original.
- Deduplicates exact files and equivalent activities across formats while retaining provenance.
- Shows dashboards, searchable activities, synchronized gap-aware sensor/respiration charts, rich FIT summaries, laps, records, routes, segments, and a combined world map.
- Deletes one activity, selected activities, or an exact snapshot of the current filtered results with an inline permanent-deletion confirmation.
- Supports separate local owner profiles and an "All profiles" aggregate view.
- Calculates an ordered catalog of cycling, running, and walking distance bests, 5-second through 2-hour power bests, and directional local segment efforts.
- Uses locally vendored MapLibre with a blank basemap by default; OpenFreeMap is a persistent, explicit global opt-in.
- Watches optional local folders without moving or deleting the files in them.
Activity Explorer does not use the Strava API, Garmin Connect API, OAuth credentials, provider passwords, automated Connect access, or proprietary Strava segments. Automatic phone-to-app synchronization is not available in 0.1.0.
Prerequisites:
- .NET SDK 10.0.302, pinned exactly by global.json.
- An official account export or one or more FIT/GPX/TCX files.
Run:
dotnet restore ActivityExplorer.slnx --locked-mode
dotnet run --project src/ActivityExplorer.WebOpen http://localhost:8342, create a profile, and open Imports. Choose Complete Garmin history, Recent files, or Local inbox. Work continues in a durable background queue, and reports remain available after completion.
On Bash shells, the same dotnet commands work unchanged.
Docker is optional:
docker compose up --buildThe compose configuration publishes only 127.0.0.1:8342 and stores application data in the activity-explorer-data volume. Stop it with docker compose down. Do not add -v unless you intentionally want Docker to delete the volume and all imported data.
By default the application uses the operating system's local application-data folder:
- Windows: %LOCALAPPDATA%\Activity Explorer
- Linux: normally ~/.local/share/Activity Explorer
- macOS: the platform local application-data location returned by .NET
Set ACTIVITY_EXPLORER_DATA to use a different absolute location:
$env:ACTIVITY_EXPLORER_DATA = "D:\ActivityExplorerData"
dotnet run --project src/ActivityExplorer.WebThe directory contains:
- activity-explorer.db: SQLite metadata and summaries.
- originals/: immutable, content-addressed activity files grouped by profile.
- staging/: temporary imports; interrupted work is retained for restart recovery.
- logs/: bounded rolling diagnostics.
- quarantine/: profile directories or unreferenced activity originals awaiting durable cleanup after database deletion.
- keys/: persistent ASP.NET Core data-protection keys; include them in a complete backup.
Back up the whole application-data directory while Activity Explorer is stopped. See Data storage and privacy.
| Input | Support |
|---|---|
| Garmin account-export ZIP | Documented uploaded-files layouts, nested archives, and irrelevant-wellness filtering |
| Strava bulk-export ZIP | Original files enriched from activities.csv |
| FIT | Official SDK parsing for timing, laps, track, sensors, respiration, temperature, calories, and training fields when recorded |
| GPX / TCX | Hardened streaming XML readers |
| GZ / ZIP | Safely expanded with traversal, symlink, nesting, count, and size limits |
Only cycling, running, and walking activities are imported. Indoor and virtual variants map to their base sport. Other sport files are reported and skipped.
See Importing data and Legal and export guides.
MapLibre renders local activity, route, and segment geometry on a blank basemap by default. In this mode every map makes zero requests to external map hosts. You can explicitly enable OpenFreeMap for all maps under Settings; the choice persists locally. Online style and tile requests reveal the viewed area to the configured provider, but do not upload stored activity files or tracks.
OpenStreetMap attribution remains visible whenever the online basemap is active. Route and other map queries are viewport-bounded, including viewports that cross the antimeridian. See Maps.
This is a no-login personal application. Localhost binding is intentional.
Do not expose it to a LAN, reverse proxy, tunnel, or the public internet. Anyone who can reach the application can view location and health data, download imported originals, edit activities, and permanently delete activities or profiles.
Activity deletion uses an inline confirmation that names the affected activity or exact selected/filtered count. Profile deletion requires entering DELETE followed by the profile name. Both are destructive. A profile JSON export describes the local records, but it is not a full backup of original files.
src/
ActivityExplorer.Core/ Domain models, DTOs, and contracts
ActivityExplorer.Infrastructure/ SQLite, imports, calculations, background work
ActivityExplorer.Web/ Blazor Interactive Server host and UI
tests/
ActivityExplorer.Tests/ Unit and SQLite integration tests
docs/ User, architecture, privacy, and legal guides
The design keeps EF entities out of Razor components and exposes testable services such as IActivityImporter, IActivityQueryService, ISegmentMatcher, IRouteService, and IStatisticsService.
dotnet restore ActivityExplorer.slnx --locked-mode
dotnet format ActivityExplorer.slnx --verify-no-changes --no-restore
dotnet build ActivityExplorer.slnx --configuration Release --no-restore -m:1 -p:BuildInParallel=false
dotnet test tests/ActivityExplorer.Tests/ActivityExplorer.Tests.csproj --configuration Release --no-build --no-restore -m:1 -p:BuildInParallel=falseFor a release candidate, also run the coverage gates, package advisory/deprecation check, isolated Playwright regressions, and loopback-only Docker smoke test documented in Testing.
No default test performs a live Garmin or Strava request. Test data is synthetic and fictional.
- Architecture
- Records methodology
- Segment methodology
- Testing
- Troubleshooting
- Dependency and license inventory
The Activity Explorer source code is MIT licensed. Dependencies retain their own licenses. In particular, Garmin's official FIT SDK uses Garmin's separate FIT Protocol License and is restored from NuGet rather than redistributed in this repository; review that license before building or distributing the application. See Dependency and license inventory.
Activity Explorer is an unofficial product and is not affiliated with, endorsed by, or sponsored by Garmin, Strava, OpenFreeMap, or OpenStreetMap. Product names are used only to identify compatible user-supplied export formats. No third-party logos, credentials, or tokens belong in this repository.