Machine learningFlutterHealth

Running an XGBoost model on a phone with no server and no ML runtime

Why we re-implemented a 300-tree model in pure Dart for an offline screening app, and how we evaluated it.

AtomToApp engineering · 4 November 2026 · 5 min read

A screening app for clinics without internet cannot call a server and should not depend on a heavy ML runtime. For HemoGuard, a thalassemia screener that reads a blood-count report, we trained an XGBoost classifier and then ran it on the phone with no TFLite and no server.

Train small, evaluate honestly

  • Seven features from a standard complete blood count (Hb, RBC, HCT, MCV, MCH, MCHC, RDW) and a dataset of roughly 500 samples.
  • A gradient-boosted tree model, which suits small tabular data far better than a neural network.
  • 92% diagnostic accuracy on held-out data that was never used for training. We report per-split metrics and failure cases, not a single number.

Walk the trees yourself

An XGBoost model is just a JSON forest. We wrote a pure-Dart inference engine that walks all 300 trees on the phone. It runs in under 50 ms per prediction, adds no native dependencies and works identically on Android and iOS.

Get the data in without typing

The app photographs the printed report, runs on-device text recognition and rebuilds the table rows from the OCR bounding boxes. A manual-entry screen with normal ranges is the fallback, and results can be exported as CSV.

Test the parser as hard as the model

Fifty-nine unit tests cover the OCR parser, the predictor and settings. In practice the parser is where field failures come from, not the model.

When this approach fits

Tabular inputs, a model that fits in memory, and a hard requirement to work offline. For images or audio we quantise and export instead, and we write the firmware side when the model has to run on a microcontroller or an edge board.

Have a similar problem?

Send a brief and the engineer who wrote this replies within one working day.

Request a quote