Back to Developer Logs

We Reverse Engineered FORM Goggles So You Don't Need a Subscription

We Reverse Engineered FORM Goggles So You Don't Need a Subscription

FORM makes the best swim goggles on the market. Full stop. The heads-up display, the stroke detection, the lap counting — it's genuinely impressive hardware that changes how you train in the pool.

The subscription to sync workouts from platforms you already pay for? Less impressive.

We decided to fix that.


The Problem

FORM goggles have a feature called Structured Workouts — you can load a set (say, 10×100m at threshold pace) onto the goggles and they'll guide you through it interval by interval while you swim. It's excellent.

The catch: if you want to push workouts from TrainingPeaks, or your coach's platform, or Flow State, you need a FORM subscription on top of whatever you're already paying. For a $200+ device, that stings.

We weren't willing to tell our swimmers "sorry, you need another subscription." So we cracked it open.


One Afternoon of Reverse Engineering

We started with the obvious question: how do FORM goggles actually communicate?

USB: a dead end. Plugged the goggles into a Linux machine and ran lsusb. Nothing interesting — the port is charge-only. No data interface whatsoever.

Bluetooth is everything. The goggles advertise as FORM-3C4 over BLE. We opened bluetoothctl, scanned, and found them immediately.

Next: enumerate the GATT profile. Using a Python library called bleak, we connected and dumped every service and characteristic the goggles expose:

Service: 00010001-8589-4d81-9803-a7a8ab3b0c06  ← vendor custom
Service: 00010002-8589-4d81-9803-a7a8ab3b0c06  ← vendor custom
Service: 00010003-8589-4d81-9803-a7a8ab3b0c06  ← vendor custom
Service: 0000180a-0000-1000-8000-00805f9b34fb  ← standard device info

Three custom vendor services. The standard Bluetooth fitness profiles (heart rate, cycling power, etc.) are nowhere — FORM built their own protocol from scratch.


Finding the Protocol

To understand a custom BLE protocol, you need the message format. We decompiled the FORM Android APK using jadx and went looking.

The entire protocol is built on Protocol Buffers — Google's binary serialization format. And the schema was right there in the decompiled code:

message FormMessage {
  bool is_command_message = 1;
  bytes data = 2;
}

enum CommandType {
  SYNC_START = 1;
  SYNC_COMPLETE = 2;
  FILE_TRANSFER_START = 22;
  FILE_TRANSFER_DONE = 23;
  FILE_TRANSFER_READY_TO_RECEIVE = 24;
  FILE_TRANSFER_SUCCESS = 25;
  // ...
}

The BLE channels: characteristic 00012001 for phone→goggles writes, 00012000 for goggles→phone notifications. Two characteristics, bidirectional, all wrapped in protobuf.


Pairing and Running a Sync

The goggles require MITM-protected BLE pairing — a security measure that shows a 6-digit passkey on the goggles HUD for confirmation. We wrote a pairing script, initiated the connection, and watched the number appear in the display. Confirmed it. Done.

From there, a full sync session took seconds:

>>> SYNC_START
>>> DEVICE_SETTINGS_REQUEST
<<< FILE_TRANSFER_START (72 bytes)
<<< [device settings: serial=Y0351300815, firmware=3.11.211]
<<< FILE_TRANSFER_DONE
>>> PLAN_INFO_REQUEST
<<< FILE_TRANSFER_START (1685 bytes)
<<< [4 chunks of workout plan data]
<<< FILE_TRANSFER_DONE
>>> SYNC_COMPLETE

16 protocol messages. Full sync. Device settings, firmware version, every workout plan stored on the goggles — all readable.

We also confirmed the write direction: using the same FILE_TRANSFER protocol in reverse, we successfully pushed a structured workout to the goggles. Chunked transfer, CRC validation, the works. The protocol is fully bidirectional.


The REST API

While we had BLE working, we got curious about the companion app's network calls. We set up mitmproxy, routed the iPhone through it, and watched the traffic.

The FORM app calls app.formathletica.com. Plain JSON REST — not encrypted binary, not obfuscated. We captured 697 requests in one session and mapped every relevant endpoint.

One nice discovery: the login endpoint accepts email + password directly, no special OAuth dance required:

POST /api/v1/oauth/token
{"email": "you@example.com", "password": "yourpassword"}
→ accessToken (30-day) + refreshToken (6-month)

No subscription check at auth time. A free FORM account is all you need.


What This Means

You can now communicate with FORM goggles from any Bluetooth-capable computer running Python. Push workouts, read device info, run a sync — without the FORM app, without a subscription.

The open-source library — formgoggles-py — is on GitHub.

# Get your token (free account works)
python3 form_sync.py --login your@email.com yourpassword

# Push a workout to your goggles
python3 form_sync.py \
  --token YOUR_TOKEN \
  --goggle-mac AA:BB:CC:DD:EE:FF \
  --workout "10x100 free @threshold 20s rest"

One command. The library handles workout creation on the FORM server, saving it to your list, fetching the protobuf binary, and pushing it to the goggles over BLE — all four steps, about 15 seconds end-to-end.

The workout string format is simple:

warmup: 200 free easy |
main: 8x100 free @fast 15s rest, 4x50 fly @max |
cooldown: 200 free easy

No subscription. No phone. No FORM app. Just Python and Bluetooth.


Flow State Integration

We built this directly into Flow State.

If you train with FORM goggles, you can now push any workout from your Flow State calendar straight to your goggles. Your AI coach builds the set, you approve it, it appears in your HUD in the water. Free. No FORM subscription.

Works for swim-specific plans, brick workouts for triathletes, and coach-prescribed sessions. Any structured swim workout in Flow State becomes a FORM workout automatically.

Try Flow State free →


A Note on Legality

I am not a lawyer. This is educational research into protocol interoperability.

We did this on our own device, on our own network, for the purpose of interoperability with third-party training software. This falls squarely within the DMCA §1201(f) interoperability exception — the same legal basis that covers Sega/Accolade, Sony/Connectix, and similar cases. We accessed no FORM servers beyond what the normal app does, and we're distributing protocol documentation and integration code, not circumvention tools.

We're not affiliated with FORM Athletica. We think they make excellent hardware. We just think interoperability should be open.

See LEGAL.md in the repo for the full analysis.