Indoor cycling · Android · Open source

Train by power.
Ride by feel.

Structured ERG workouts for your smart trainer, defined as plain JSON, ridden against your FTP, and saved to your phone. No subscriptions, no accounts, no cloud required.

Wahoo Kickr Core ready BLE FTMS Local-first

What's inside

Built for the saddle, not the screen.

Every screen is designed for arm's-length legibility on a sweaty phone. Telemetry first, decoration last.

BLE smart trainer

Standard FTMS over Bluetooth LE. Pair your Wahoo Kickr Core or any FTMS-compatible trainer. No vendor SDK, no Google Play Services.

ERG mode control

The app drives your trainer to hit each interval's target wattage automatically. You hold the cadence, it holds the watts.

Power zones

Z1 recovery through Z7 neuromuscular, calibrated as percentages of your FTP. Visualised on every workout, every interval, every chart.

JSON workouts

Every workout is a readable JSON file. Use the bundled library, drop in your own, hand-craft them in a text editor, or build them visually with the workout editor.

Zwift Click ready

Pair a Zwift Click v1 controller to nudge target power up or down mid-interval. On-screen +/- buttons work too. Your handlebar, your call.

Yours, locally

Rides, FTP, weight, paired devices: all on your phone. No telemetry leaves the device. Optional sync is opt-in and lazily loaded.

Workout library

Familiar formats. Honest names.

Sweet Spot, Threshold, VO2. The same intervals you already know from other training apps, structured against your FTP and ridden in the same colour-coded zones.

Threshold

Sweet Spot 3×12

52 MIN · TSS 65 · IF 0.91

225avg watts
92avg rpm
3intervals

VO2 Max

30/30s · 8 sets

38 MIN · TSS 58 · IF 0.94

118%FTP peak
8sets
30son/off

Build your own

Visual workout editor

Lay out intervals as coloured blocks in your browser, tweak the durations and percentages until the shape feels right, and send the result to your phone. No account, no upload - the workout file is yours to keep, ride, or hand around.

Open the editor

Browse community

Workouts shared by other riders

Coaches and other riders publish packs of structured workouts that anyone can browse. Open a pack, scroll through the rides it contains, and tap to add the ones you want. Each workout becomes a local copy on your phone the moment you add it - yours to ride or edit, and not affected if the original pack changes later.

Browse community
Z1 Recovery Z2 Endurance Z3 Tempo Z4 Threshold Z5 VO2 Z6 Anaerobic Z7 Neuro

From install to first sprint

Four steps. No accounts.

Install the APK, pair your trainer, pick a workout, ride. No sign-up screens, no subscription paywalls, no welcome carousels.

Install

Get the app from F-Droid (or sideload the APK from a release). Open it. The first screen asks for your FTP and weight. That's it.

Pair

Tap the trainer icon. Power on your Kickr Core, the app discovers it over BLE, and remembers it. Optionally pair a HRM and a Zwift Click.

Pick

Browse the workout library. Each card shows the zone profile, duration, TSS, and IF. Pick one that fits your session and your legs.

Ride

Hit start. ERG holds the target wattage. The HUD shows zone, power, cadence, HR, and time-in-step. The completed ride saves locally as a file.

F-Droid native

No tracking. No accounts. No exceptions.

Indoor Bike was designed from day one to ship through F-Droid. That means no proprietary blobs, no Google Play Services, no analytics SDKs, no crash reporters phoning home.

  • Local-first storage. Your FTP, weight, paired devices, and ride history live on your phone.
  • No Google services. Standard Android BLE APIs. No FCM, no Firebase, no Crashlytics.
  • Open source. Kotlin Multiplatform core and Jetpack Compose UI. Read it, fork it, build it yourself.
  • Optional, opt-in sync. Account login (Auth0) and cloud backup (CleverCloud) are off by default and lazily loaded only if you enable them.
  • Open file formats. Workouts are JSON. Saved rides are files you can copy off the device any time.

Read the full privacy policy →

Questions

Good to know.

Which trainers are supported?

Any smart trainer that speaks the standard Bluetooth LE FTMS profile. The first-class target is the Wahoo Kickr Core; other FTMS-compatible trainers should work but aren't extensively tested yet.

Do I need an account?

No. The app is fully functional offline with no sign-up. Optional Auth0 login and CleverCloud sync exist for users who want cross-device backup, but everything works without them.

Where do I get the app?

The app is being prepared for F-Droid. Once published, the install link will appear here. Until then, you can build the Android project from source.

Can I use my own workouts?

Yes. Workouts are plain JSON files describing a sequence of intervals (duration + power as % of FTP). Drop them into the workouts directory and they show up in the library, or build them visually in the browser editor and send them to the app.

Is iOS supported?

Not yet. The shared core is built with Kotlin Multiplatform Mobile so an iOS port is planned, but the current focus is shipping a polished Android release first.

What about heart-rate monitors?

Standard BLE HRMs (including the Garmin HRM) pair the same way as the trainer. HR shows on the ride HUD and is recorded with the ride file.

Ready when you are.

Install with Obtainium to get the app and automatic updates straight from our Codeberg releases - no store account, no Google services. An F-Droid release is also in preparation.

New to Obtainium? Install it, tap Add App, and paste https://codeberg.org/juhanilehtimaki/IndoorCyclingApp.