Skip to main content

File formats

Navigator reads two file types and writes two. This page describes what its parsers actually look at — useful when a file will not import, or when you are generating one from something other than ForeFlight.

Routes — .fpl / .xml

The Garmin/ForeFlight flight plan format: XML with a waypoint table.

Navigator's parser walks the document and collects every <waypoint> element, reading three child elements from each:

ElementRequiredNotes
<identifier>YesBecomes the waypoint's displayed name. Must be non-empty.
<lat>YesSigned decimal degrees
<lon> or <long>YesSigned decimal degrees. Both spellings accepted.

A minimal file Navigator will accept:

<?xml version="1.0" encoding="utf-8"?>
<flight-plan xmlns="http://www8.garmin.com/xmlschemas/FlightPlan/v1">
<waypoint-table>
<waypoint>
<identifier>KAAA</identifier>
<lat>42.223</lat>
<lon>-83.746</lon>
</waypoint>
<waypoint>
<identifier>ALPHA</identifier>
<lat>42.401</lat>
<lon>-83.512</lon>
</waypoint>
</waypoint-table>
</flight-plan>

Things to know:

  • Order is document order. Waypoints are used in the order their <waypoint> elements appear, and legs are built between consecutive pairs. Navigator does not read the <route> / <route-point> section, so the route it flies is the waypoint table's order. For a normal ForeFlight export these are the same thing.
  • A waypoint that appears twice in a route appears once here. A route that returns to a waypoint it has already used will lose that repetition, because the waypoint table lists each waypoint once.
  • Waypoints missing an identifier or unparseable coordinates are skipped silently.
  • Fewer than two usable waypoints is an error, reported as a parse failure.
  • Elements the parser does not read — <type>, <country-code>, <elevation>, <route-name> — are ignored, so extra content does no harm.

Track logs — .kml

Navigator expects a ForeFlight-style track log: a gx:Track whose <when> timestamps and <gx:coord> positions alternate.

<gx:Track>
<when>2026-05-20T14:25:59.15Z</when>
<gx:coord>-90.490578 41.451015 176.4</gx:coord>
<when>2026-05-20T14:26:00.15Z</when>
<gx:coord>-90.490578 41.451012 176.4</gx:coord>
</gx:Track>

The parser handles two cases, in order of preference:

  1. gx:Track pairs<when> (or <gx:when>) paired positionally with <gx:coord> (or <coord>). This is the normal path.
  2. Leftover times paired with <coordinates> — any <when> values not consumed above are paired with whitespace-separated tokens from plain <coordinates> blocks. This is what lets a file that carries its geometry and its clock in separate elements still be read.

A file with no <when> elements at all is rejected. See the note below.

Coordinate order is KML's: longitude first, then latitude, with an optional third altitude value. <gx:coord> is space-separated, <coordinates> comma-separated; both are accepted. Altitude is read and kept with the track, but nothing in scoring uses it — every penalty is computed in two dimensions.

Timestamps are parsed as ISO 8601, with or without fractional seconds. A missing timezone is treated as UTC.

Two hard requirements:

  • At least one valid coordinate/timestamp pair, or the import fails with "No coordinate/time pairs found in KML."
  • Timestamps must be strictly increasing. A duplicate or out-of-order timestamp fails the import with "Non-increasing timestamps at index n." A track stitched together from two recordings, or one containing a paused-and-resumed segment, will trip this.
A KML without timestamps is refused, not guessed at

Scoring is a timing exercise, so a track log with positions and no clock cannot be graded. Navigator says so at import — "This track log has positions but no timestamps, so it cannot be timed or scored" — rather than accepting the file.

Earlier builds instead invented timestamps one second apart. That kept a positions-only KML from failing outright, but the flight then scored with correct positions and meaningless times, and nothing warned you, because a synthetic 1 Hz track is strictly increasing and passes every validity check. A live flight saved by one of those builds will not re-grade.

Exports

JSON from the results screen

Prepare JSON Export → Share JSON on the post-flight results screen writes NavScore.json: the complete FlightScore and nothing else — every per-leg result, every checkpoint penalty, the totals, and each point category.

{
"legResults": [
{
"id": 0,
"fromWaypoint": "KAAA",
"toWaypoint": "ALPHA",
"scored": true,
"plannedSeconds": 600,
"actualSeconds": 612,
"deviationSeconds": 12,
"absoluteDeviationSeconds": 12,
"timingPenaltyPoints": 12
}
],
"checkpointPenalties": [
{
"checkpointNumber": 1,
"waypoint": "ALPHA",
"scored": true,
"closestNM": 0.41,
"penaltyPoints": 0
}
],
"plannedTotalSeconds": 1800,
"actualTotalSeconds": 1809,
"totalDeviationSeconds": 9,
"totalAbsoluteDeviationSeconds": 23,
"legTimingPenaltyPoints": 23,
"elapsedTimePenaltyPoints": 9,
"checkpointPenaltyPoints": 163.7,
"secretCheckpointPenaltyPoints": 100,
"fuelError": 1,
"fuelPenaltyPoints": 25.6,
"totalPenaltyPoints": 321.3
}

Keys are sorted and the output is pretty-printed, so two exports of the same flight diff cleanly. All times are seconds, all distances nautical miles, fuelError is signed gallons.

JSON from the live results sheet

Export JSON after ending a live flight writes Flight.json — a whole SavedFlight record, which wraps the same score object above alongside the flight's id, name, date, planned leg inputs, settings, secret checkpoint counts, and fuel figures. Dates are ISO 8601.

This is the more useful export to attach to a question about a result, because it carries the inputs as well as the outputs.

KML from the live results sheet

Export KML writes Flight.kml, openable in Google Earth, ForeFlight, or anything else that reads KML. The same bytes are what Save to Flights stores with a live flight.

The recorded track is written twice, in one Document:

  • a gx:Track of paired <when>/<gx:coord> elements carrying each fix's real timestamp and its GPS altitude — the same shape ForeFlight exports, and a valid scoring input;
  • a LineString of the same points, so viewers that do not understand gx:Track still draw the route as a line.

Reading it back gives the timing the flight was scored with in the air. Fixes that do not advance the clock — a repeated or out-of-order sample — are dropped on the way out, since they carry no timing information and would trip the strictly-increasing rule above. A fix recorded without a vertical solution is written with a zero altitude.