Skip to content

Mapping guides

Bidirectional mapping to and from incumbent schemas is OpenBody’s primary success measure and its adoption wedge: the standard is a universal adapter. These guides are built from the real mappers in openbody-ts/src/mappers — pure input → { records, warnings } functions, round-trip tested (npm test). Structurally unusable input throws a typed MapperInputError; anything merely degraded, skipped, or defaulted is reported on the returned warnings channel instead. The mappers resolve source exercise names to canonical registry ids where the registry covers them, falling back to the lossless opaque form otherwise.

Supported formats

All mappers are importable from the openbody-ts package root and run in both node and the browser. The in-browser converter wires all of them to a drag-and-drop page. (Bundling the package for the browser needs a toolchain that understands JSON import attributes — import … with { type: "json" }, used for the vendored schema and crosswalk; modern esbuild / Vite / Rollup / Webpack 5 all do. Node needs nothing extra.)

FormatDirectionWorks inCaveats
Hevy (workout CSV)importlibrary + browser tool
Strong (workout CSV)importlibrary + browser tool,- or ;-delimited exports both parse
Strava (activity + streams JSON)importlibrary + browser toolthe library maps the API’s activity+streams responses (streams must include time); the browser tool reads the bulk-export activities.csv instead
Apple Health / Health Connect (export.xml)importlibrary + browser tool
FIT (recorded activity or structured workout)importlibrary + browser toollibrary takes pre-decoded FIT messages (why); the browser tool decodes the .fit binary for you but maps recorded activities only
GPX (GPS track)importlibrary + browser tooluntimed tracks degrade honestly (no fabricated timing)
TCX (Garmin Training Center XML)importlibrary + browser tool
Fitbit (Google Takeout folder)importlibrary + browser toolmulti-select the Takeout JSON files; timestamps need a utcOffset
Concept2 (Logbook season CSV)importlibrary + browser toolone row per workout — per-stroke detail isn’t in this export
theCrag (logbook CSV)importlibrary + browser tool
Strong (CSV out — also imports into Hevy)exportlibrary + browser toolbest-effort by design: losses reported machine-readably (contract)

The browser tool accepts every import format above — Hevy, Strong, Apple Health, Strava, GPX, TCX, FIT, Concept2, theCrag, and Fitbit (Google Takeout) — decoding each entirely in your browser, and it re-imports an OpenBody JSON you exported earlier. CSV timestamps carry no UTC offset at the source, so the CSV-based mappers take an optional utcOffset and are timezone-independent — the same bytes map to the same records on any machine.

Mapping principles (§10.1)

  • Canonical-plus-residue. Map each source construct to its canonical OpenBody equivalent; carry anything with no canonical home in namespaced extensions or, for identity, the opaque fallback. Nothing is dropped.
  • Lazy terminology. Source type tokens are preserved source-namespaced on ingest and resolved to external codes (LOINC / SNOMED / UCUM / MET) only on output.
  • Provenance preserved. Source platform, app, and device become registry-backed provenance tokens; the source’s own key becomes clientRecordId.
  • Round-trip. Source → canonical → source MUST preserve meaning under the §8.3 equivalence rule.

The guides