Concepts

Data model & export

Everything TripLibre knows is in one SQLite file. The export bundle is that same data as CSV, JSON and GeoJSON, with stable IDs that join across every table.

Conventions

FieldConvention
*_tsUTC Unix seconds (REAL). Exports add a matching *_utc ISO string.
tzIANA time zone of the device when recorded. Local dates and hours use each record's own tz, so travel across zones stays correct.
CoordinatesWGS84 decimal degrees
DistancesMetres, great-circle (haversine, R = 6 371 008.8 m)
IDsLowercase UUID strings for visits, trips, places…; integers for raw points
route_polylineGoogle encoded polyline, precision 1e-5, simplified with Douglas–Peucker (8 m)
DeletesSoft: deleted = 1. audit_log keeps every old → new value.

The database is at Library/Application Support/HHT/travel.sqlite (WAL mode). The schema version is in PRAGMA user_version; migrations are append-only.

Core tables

TableOne row perKey columns
raw_location_pointsGPS fixts, lat, lon, h_accuracy, speed, source, collector_mode, tz
motion_activitiesCoreMotion episodets, activity, confidence
placesPlaceid, name, lat, lon, radius_m, category, code, merged_into
visitsStay at a placeid, place_id, arrival_ts, departure_ts, purpose, user_status, deleted
tripsMovement between visitsid, origin_visit_id, destination_visit_id, departure_ts, arrival_ts, distance_m, mode_auto, mode_user, purpose, route_polyline
trip_segmentsMode segment inside a triptrip_id, seq, start_ts, end_ts, mode_auto, mode_user, distance_m
flightsFlighttrip_id, date, origin_code, destination_code, airline, flight_number, distance_m
stampsOne-tap self-report (schema v3)id, ts, lat, lon (coarse, ≈ 110 m), uncertainty_m, fix_accuracy_m, fix_age_s, visit_id (set by inference; NULL = unmatched), note, deleted
life_phasesNamed date rangename, kind, start_date, end_date
audit_logCorrectionts, entity_type, entity_id, action, field, old_value, new_value

The final mode of a trip is COALESCE(mode_user, mode_auto, 'unknown'). The full column-by-column reference is in docs/data-model.md.

Codes

Modes: walk run bicycle ebike scooter car car_driver car_passenger taxi bus subway light_rail commuter_rail intercity_rail coach shuttle ferry airplane other unknown

Purposes: home work school meal shopping recreation social personal_business medical travel transfer escort other

Place categories: home work_school restaurant cafe grocery shopping recreation entertainment airport rail_station transit_station hotel friend_family medical other stadium event_venue museum library convenience_store gas_station bar gym pharmacy bank civic religious parking

Views

The export bundle

Settings › Create export writes hht-export-YYYYMMDD-HHMMSS/. Every column, with units, missing-value rules and synthetic examples, is in the Data dictionary.

FileContents
trips.csvThe canonical HHTS-style trip table: person_day_id, trip_seq, OD places, UTC and local times, travel_time_min, distance_m, mode, mode_group, segment_modes, purpose, provenance
trip_segments.csvMode segments with their own times, distances and polylines
visits.csv, places.csvStays and places (with visit counts and first/last visit)
flights.csv, life_phases.csv, audit_log.csvAs in the database
stamps.csvSelf-reported stops (coarse location only); visit_id is the visit inference attached each one to, empty if unmatched. Loaded as d.stamps in Python
raw_location_points.csv, motion_activities.csvOnly if Include raw GPS points is on
data.jsonEverything above in one JSON document
places.geojson, trips.geojson, trip_ends.geojsonFor QGIS, kepler.gl, Mapbox…
travel.sqliteA complete snapshot of the database, including raw points, whatever the range and raw-points settings. Delete it before sharing a limited export (see Privacy)
README.txtWhat each file is

Analysing in Python

cd analysis
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python explore.py ~/Downloads/hht-export-20260927-120000
from hht import load, summary, mode_share

d = load("~/Downloads/hht-export-20260927-120000")  # export folder, or a travel.sqlite file
d.trips.head()                       # one row per trip
summary(d.phase("Fall 2026"))        # trips/day, km/day, radius of gyration, entropy…
mode_share(d.trips, by="distance_m") # or "trips", "travel_time_min"

The full Python API is on the Developer API page.

Analysing with SQL

Open travel.sqlite in DuckDB, R (DBI), QGIS or the sqlite3 CLI and use the views:

-- mode share by trips for the last 30 days
SELECT mode_final, COUNT(*) AS trips, ROUND(SUM(distance_m) / 1000, 1) AS km
FROM v_trips
WHERE departure_ts >= strftime('%s', 'now', '-30 days')
GROUP BY mode_final
ORDER BY trips DESC;
✓

audit_log is a ready-made labelled dataset: every set_mode row is a ground-truth mode for a trip, which is useful for evaluating or training a better mode classifier.

Metric definitions

MetricDefinition
Person-dayLocal date with ≥ 1 trip or visit. Per-day rates divide by person-days, not calendar days.
Mode shareBy trips, distance or time, on the final mode; also by group (active / car / transit / long-distance / other).
Radius of gyration√(Σ wᵢ d(pᵢ, c)² / Σ wᵢ) over visited places, dwell- and visit-weighted.
Activity spaceConvex hull area of visited places.
Destination / mode entropyShannon entropy (bits) of visits per place / trips per mode.
Time away from home24 h − time at home places, over days with a home visit.
Home-based tourTrips from leaving home to next arriving home; complex tour = ≥ 2 stops.
Repeat OD shareShare of trips whose origin→destination pair already occurred earlier in the period.

All definitions: docs/analytics.md.