Reference

Data dictionary

What you get when you export from TripLibre: each file, each column, and the rules for times, units, IDs and missing values. Written for researchers receiving an export. It describes schema version 5, the current one.

For the database internals (every table and migration), see docs/data-model.md. For a shorter overview, see Data model & export. All examples on this page come from the synthetic test fixture that CI exports on every run, not from a real person.

Concepts

TermDefinition in TripLibre
Raw observationA GPS fix (raw_location_points) or a CoreMotion activity episode (motion_activities). Append-only: never edited or thinned.
Inferred recordA visit, trip or segment produced by the inference engine (user_status = auto). Can be rebuilt from raw data at any time.
User correctionA record the user confirmed, edited or created (user_status = confirmed, edited or manual), or deleted (deleted = 1). Locked against rebuilds. Each change is a row in audit_log.
VisitA stay of at least 5 minutes within about 100 m (the default stay radius) of one spot. HHTS: an activity location.
PlaceA location visits are matched to. Named and categorised by the user, or unnamed.
TripMovement from one visit to the next. HHTS: a linked trip, possibly with several modes.
SegmentA single-mode part of a trip (an unlinked trip). A walk–subway–walk trip has three.
ModeThe trip's main mode, chosen from its segments by the hierarchy air > rail > transit > car > bike > walk.
Person-dayA local calendar date (in the record's own time zone) with at least one trip or visit. person_day_id is that date.
TourA home-based tour: the trips from leaving a Home place to the next arrival at a Home place. Computed in analytics, not stored in the export.
StampA one-tap self-report that a stop happened "around here, around now". Coarse location only.

Conventions

TopicRule
IDsLowercase UUID strings for places, visits, trips, segments and stamps. They are stable across exports, so files from different days can be joined. Raw points, motion rows and audit rows use integer IDs.
*_ts, tsUnix seconds, UTC (decimal). In CSV files each one is followed by an ISO-8601 UTC string: arrival_ts → arrival_utc, ts → time_utc.
created_at, updated_at, inserted_atUnix seconds, UTC, with no ISO companion. Bookkeeping only.
*_localISO-8601 with offset, in the time zone in tz.
tzIANA zone of the phone when the record was made, e.g. America/New_York. Local dates use each record's own zone, so trips across zones stay correct.
DatesYYYY-MM-DD, local (person_day_id, flights.date, life_phases.start_date).
CoordinatesWGS84 decimal degrees. trips.csv rounds them to 6 decimals; stamps to 3 (≈ 110 m). GeoJSON uses [lon, lat].
UnitsDistances in metres; speeds in m/s; accuracies in metres; durations in minutes (*_min) or seconds (*_s).
DistanceAlong the recorded path, great-circle between fixes; a straight line across a data gap.
route_polylineGoogle encoded polyline (precision 1e-5), simplified (Douglas–Peucker, 8 m).
Booleans0 / 1.
Confidence0–1. Higher is more certain; trips below the review threshold are flagged in the app.

Missing values

Deleted and merged records

The export folder

Settings › Create export writes hht-export-YYYYMMDD-HHMMSS/ (the phone's local time) to Files › On My iPhone › TripLibre › Exports:

FileFormatRange filter applies?Contents
trips.csvCSVYesOne row per trip, HHTS-style.
trip_segments.csvCSVYesMode segments of each trip.
visits.csvCSVYesStays.
places.csvCSVNoAll active places, with visit counts.
stamps.csvCSVYesSelf-reported stops.
expenses.csvCSVYesCosts the user entered.
flights.csv, life_phases.csv, audit_log.csvCSVNoAs stored.
raw_location_points.csv, motion_activities.csvCSVYesOnly when Include raw GPS points is on.
data.jsonJSONVisits, trips, segments, stamps, expensesAll tables except raw points and motion.
places.geojson, trips.geojson, trip_ends.geojsonGeoJSONTrips onlyPoints and LineStrings for GIS.
travel.sqliteSQLiteNoThe complete database, raw points included, whatever the options.
README.txtText—A short guide to the files.
!

The Last 30 days range and the Include raw GPS points switch don't apply to travel.sqlite. If you're sharing a limited export, delete travel.sqlite first. Selective export is Planned.

trips.csv

One row per non-deleted trip, ordered by departure. Example values are from the synthetic fixture.

ColumnMeaningExample
person_day_idLocal date of departure2026-09-15
trip_idTrip UUID25da27b4-…
trip_seqOrder within the person-day, from 11
origin_visit_id, destination_visit_id→ visits.csv. Empty for imported or hand-made history02db441f-…
origin_place_id, origin_place_name, origin_categoryOrigin place (→ places.csv)…, Home, home
origin_lat, origin_lonOrigin visit centroid (else place), 6 decimals39.952611, -75.165261
destination_*Same five columns for the destinationPenn, work_school
departure_utc, arrival_utcISO-8601 UTC2026-09-15T12:00:15Z
departure_local, arrival_localISO-8601 with offset, in tz2026-09-15T08:00:15-04:00
tzIANA time zoneAmerica/New_York
day_of_week1 = Sunday … 7 = Saturday, local3
travel_time_minArrival − departure, minutes (2 decimals)27.50
distance_mPath distance, metres (1 decimal)2415.8
modeFinal mode: mode_user, else mode_auto, else unknownbicycle
mode_groupactive, car, transit, long_distance, otheractive
mode_auto, mode_confidenceClassifier output and its confidencewalk, 0.85
mode_userUser's correction, if anybicycle
n_segments, segment_modesSegment count and their modes joined by |1, bicycle
purposeExplicit trip purpose, else destination visit purpose, else the place category's defaultwork
has_gap1 if GPS was silent for more than 15 minutes during the trip0
auto_confidenceEngine's confidence in the trip itself0.95
sourceinferred, manual or imported_csvinferred
user_statusauto, confirmed, edited or manualedited
notesUser's free text(empty)
route_polylineEncoded routeyfzrFzuwiM`AhxBE~UTdKGzP

Other CSV files

visits.csv

visit_id, place_id, place_name, place_category, place_category_custom, arrival_ts, arrival_utc, departure_ts, departure_utc, tz, duration_min, lat, lon, purpose, auto_confidence, source, user_status, point_count, notes. lat/lon is the observed centroid of the stay; point_count the number of fixes in it.

trip_segments.csv

segment_id, trip_id, seq, start_ts, start_utc, end_ts, end_utc, mode, mode_auto, mode_confidence, mode_user, distance_m, route_polyline. seq starts at 0. Segments of a trip are contiguous and don't overlap. A segment with mode_user set and no mode_auto was drawn by hand.

places.csv

place_id, name, category, category_custom, code, lat, lon, radius_m, address, city, region, country, favorite, source, merged_into, notes, created_ts, created_utc, visit_count, first_visit_ts, first_visit_utc, last_visit_ts, last_visit_utc. Address fields are filled only if the user turned on address lookup. code is an IATA or station code.

stamps.csv

stamp_id, ts, time_utc, tz, lat, lon, uncertainty_m, fix_accuracy_m, fix_age_s, visit_id, note. lat/lon are rounded to 3 decimals and empty if there was no fix in the last 10 minutes. visit_id is the visit inference attached the stamp to, empty if none.

expenses.csv

expense_id, ts, time_utc, tz, amount, currency, category, trip_id, visit_id, note. One row per cost the user entered (schema v6). currency is an ISO 4217 code; amounts in different currencies are never converted. amount 0 means the user said it was free (a pass, a lift), which differs from no row at all. category is fare, taxi, fuel, parking, flight, lodging, food, admission, shopping or other. A cost is on a trip_id, a visit_id, or neither (a cost on that day, dated by ts); an id is empty unless it points at an exported trip or visit. ts is the trip's departure, when the stay began (or when it was entered, during an ongoing stay), or the time the user chose.

raw_location_points.csv

id, ts, time_utc, lat, lon, h_accuracy, altitude, v_accuracy, speed, speed_accuracy, course, source, collector_mode, tz, inserted_at. source is gps, significant_change, region_exit, visit_arrival, visit_departure, stationary_marker or imported_gpx. collector_mode (moving / stationary) says whether a silence afterwards was deliberate.

motion_activities.csv

id, ts, time_utc, activity, confidence. activity is stationary, walking, running, cycling, automotive or unknown; confidence 0 (low) to 2 (high). Each row lasts until the next one.

audit_log.csv

id, ts, time_utc, entity_type, entity_id, action, field, old_value, new_value. One row per correction. entity_type: visit, trip, trip_segment, place, flight, stamp. action includes set_mode, set_purpose, set_place, set_times, merge, split, delete, confirm, create. Values are stored as text and may contain place names or IDs.

flights.csv and life_phases.csv

Flights: flight_id (repeated as id), trip_id, date, airport codes and coordinates, times, airline, flight number, aircraft, seat, cabin, distance_m, booking_reference, notes, source. Life phases: id, name, kind, start_date, end_date (inclusive; empty = ongoing), notes.

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. The classifier only produces a subset; see known limitations.

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. Codes are never renamed between versions.

JSON, GeoJSON and SQLite

data.json

One object: format ("hht-personal-travel-diary"), schema_version, exported_at, range (null for everything), then one array per table: places, visits, trips, trip_segments, flights, journeys, journey_members, life_phases, stamps, expenses, audit_log. Rows are the database columns as stored: times are Unix seconds, and trips.purpose is the explicit purpose only (the CSV's purpose is the resolved one).

{"format": "hht-personal-travel-diary", "schema_version": 5, "range": null,
 "trips": [{"id": "25da27b4-…", "departure_ts": 1789473615, "arrival_ts": 1789475265,
            "mode_auto": "walk", "mode_user": "bicycle", "purpose": null, "deleted": 0, …}], …}

GeoJSON

travel.sqlite

A full copy of the app's database. Open it with sqlite3, DuckDB, R (DBI), pandas or QGIS. The views v_trips and v_visits leave out deleted rows and add mode_final, purpose_final and duration_s.

Loading in Python

from hht import load

d = load("hht-export-20260915-210000")   # export folder, or a travel.sqlite file
d.trips       # trips.csv, times parsed as UTC
d.segments    # trip_segments.csv
d.visits, d.places, d.flights, d.life_phases
d.stamps      # self-reported stops
d.expenses    # costs entered by the user
d.points      # raw GPS, None if not exported
d.motion      # CoreMotion episodes

analysis/hht.py reads both formats into the same columns. make export-check verifies on every CI run that the CSV and SQLite versions of one export agree. More helpers are on the Developer API page.

Schema versioning