Swingman
Data

Blog ·

Reading launch-monitor CSV exports: what Swingman looks for

Every launch-monitor app exports a CSV, and every one is different. How Swingman recognises columns by alias, detects units, fills in missing spin numbers and maps club names, and why a real export from your device helps.

A live connection is the nice path for launch-monitor data. The realistic path, at a driving range with a phone and no laptop, is the CSV your monitor's app exports when the session is over. Swingman imports those and runs the same coach on them as on a live session; matching the rows to the swings the camera caught is the next step. This post is how the importer reads a file it has never seen, and what makes it fail.

The problem

There is no standard. The same quantity turns up as Ball Speed, ball speed (mph), BallSpeed, Speed and Ball. One app writes Launch Angle, another VLA, a third Vertical Launch Angle. Headers change with the app's language setting. Units hide in the header, in a settings screen, or nowhere. Dates are one column or two.

Writing a parser per device would mean a parser per firmware version. Instead the importer recognises fields by aliases.

Step 1: normalise the header

Each header is lower-cased, anything in brackets is removed, and everything that isn't a letter or digit is dropped. So Ball Speed (mph) becomes ballspeed, Club Head Speed becomes clubheadspeed, and Launch Angle (°) becomes launchangle. Then each normalised header is looked up in an alias table, and the first match wins. Part of the table:

FieldAliases recognised today
Ball speedballspeed, ballspeedmph, ball, speed
Launch anglelaunchangle, vla, verticallaunch, verticallaunchangle, launch
Launch directionlaunchdirection, hla, horizontallaunch, horizontallaunchangle, direction, sideangle, azimuth
Back spinbackspin, backspinrpm
Side spinsidespin, sidespinrpm
Total spintotalspin, spinrate, spin, spinrpm
Spin axisspinaxis, axis, spinaxisdeg
Carry / totalcarry, carrydistance, carryyds, carryyards / total, totaldistance
Club speedclubspeed, clubheadspeed, swingspeed, clubspeedmph
Attack angleattackangle, angleofattack, aoa
Face to targetfacetotarget, faceangle, face, clubface
Club pathclubpath, swingpath, path
Dynamic loftdynamicloft, loft, dynloft
Smash factorsmashfactor, smash
Face impactimpactvertical, verticalimpact, verticalfaceimpact / impacthorizontal, horizontalimpact, horizontalfaceimpact
Clubclub, clubname, clubtype
Whendatetime, timestamp, shottime, created, createdat; or date + time

A new export with an unfamiliar header is a one-line change: add the alias. That is the whole design, and it is why we ask owners to send a file rather than a screenshot.

Step 2: work out the units

If any header mentions metres ((m), meters, metres) and none mentions yards, distances are metres; otherwise yards. Speeds are mph unless a header says km/h or m/s, in which case they are converted. You can override both when importing, because some apps write the unit in a settings screen and nowhere in the file.

Step 3: fill in the spin

The coach reasons about total spin and spin axis, which is how Open Connect, the live protocol, expresses spin. Many exports give back spin and side spin instead. The importer derives what is missing:

The reverse happens when a file gives total spin and axis and the coach needs the components. Nothing is invented: a file with neither total spin nor back spin gets null spin, and the rules that need spin skip that shot rather than guess.

Step 4: the two fields that must exist

A row without ball speed or launch angle is skipped and reported. Everything else can be missing: club data is optional (a ball-only device still gets slice, hook, pull, push, low-launch and strike diagnoses at lower confidence), and clubs fall back to whatever you chose for the import.

Step 5: club names

Driver, DR, 1W and D all become DR. 7 iron, 7i and 7I become 7I. 56°, 56 deg wedge become W56. Pitching, gap, sand and lob wedges map to PW, GW, SW and LW. Anything two or three characters long and alphanumeric is kept as typed, so an app's own code survives. The rest becomes "unknown club", and you pick one for the session.

Step 6: when

If there is a datetime-like column it is parsed as the shot time. If there are separate date and time columns they are joined. Exports with neither import fine; the shots just have no clock time. When matching to camera footage arrives it will work by order first, the first exported shot being the first swing the camera kept, with timestamps as anchors where they exist and your corrections where the counts differ. That is how Toptracer sessions are paired to footage today, and the CSV path will reuse it.

What the raw file gets you

The import reports which header became which field and which rows were skipped and why, so a misread is visible rather than silent. When a header is misread, the fix is an alias; when a unit is misread, the fix is a flag. Both are one-line changes.

Devices and exports we know about

If you own any of these, one session's export (any length, any club) lets us verify the format and publish a connection guide on the works-with page. Send it over. The file is used to check the import and then kept only as long as you want it to be.

Questions or a correction? Get in touch.