#barcode#foss#android#scanner#comparison

Barcode scanner accuracy across FOSS calorie trackers

Eight FOSS Android apps, 50 barcodes, four lighting conditions. Some scanners ship without ZXing optimisations and it shows.

Method

Fifty packaged foods, all with valid GTIN-13 barcodes, scanned three times each on each app under four lighting conditions:

  • L1: bright overhead, white kitchen counter
  • L2: warm yellow incandescent (typical evening)
  • L3: dim — phone screen as the only light source
  • L4: outdoor shade with the package angled

Phone: Pixel 7a, GrapheneOS, no Play Services. Distance ~15 cm. Stopwatch from app foreground to “barcode recognised.”

Test ran March 7–9, 2026.

Apps tested

OpenNutriTracker, Waistline, Foodvore, FoodSnap-Lite, plus four smaller projects we don’t recommend by name in this post because their scanners are bad enough that the names would just be defamatory.

Numbers

AppL1 read rateL2L3L4Median timeOffline?
OpenNutriTracker49/5047/5041/5045/501.6sYes
Waistline48/5046/5043/5044/502.4sYes
Foodvore47/5042/5033/5040/502.0sNo
FoodSnap-Lite46/5040/5028/5038/501.9sNo
Small project A38/5030/5014/5025/503.4sYes
Small project B31/5022/509/5018/504.1sYes
Small project C18/509/502/507/506.0sYes
Small project Dn/a (crashed in L3)

The good apps cluster around the 90–98% read-rate range under decent light and degrade gracefully in the dim case. The bad ones fall off a cliff.

Why the spread

Three things separate good FOSS barcode scanners from bad ones in this category:

1. Library choice. Apps using ZXing (the canonical Java/Kotlin barcode library) and the modern fork ZXing-Android-Embedded all read well. Apps using their own homegrown image processing perform poorly. There is no surprise here.

2. Pre-processing. OpenNutriTracker, Waistline, and Foodvore apply contrast normalisation and adaptive thresholding to the camera feed before passing the frame to the decoder. Apps that skip this stage are roughly 30 percentage points worse in dim conditions.

3. Auto-focus and frame buffering. The good apps continuously buffer 5–10 frames, decode in parallel, and accept the first successful read. The bad apps wait for one in-focus frame and decode that, which is why they’re 2–4× slower and miss the dim cases.

Online vs offline

Two of the eight apps phone home for the OFF lookup before showing the scanned barcode. In airplane mode, you can scan but not log. This is documented in their READMEs but it surprises people. OpenNutriTracker and Waistline both work fully offline if the food is already in your local cache or if you’ve ever logged the barcode before.

For travel and gym-locker-room usage, offline matters. We weight it heavily.

ZXing vs ML Kit

A note on Google’s ML Kit barcode scanner: it’s faster and more robust than ZXing in our testing. None of the FOSS apps use it, because ML Kit pulls in Google Play Services and that is — correctly — a deal-breaker for the F-Droid audience. The performance gap is real but the privacy trade-off is also real.

What about commercial apps?

We didn’t include them in the table because the test design (timed reads + read-rate counts) gets contaminated by paywalls and onboarding modals. But for reference: MyFitnessPal Premium and Lose It! both use proprietary scanners that read at roughly the OpenNutriTracker level. Cronometer’s scanner is slower and has worse dim-light performance than Waistline. None of them are dramatically better than the FOSS leaders.

Recommendations

  • Use OpenNutriTracker if you scan in normal light and want it fast.
  • Use Waistline if you scan in mixed conditions and want offline-first.
  • Don’t use the small projects — any of them — unless you want to debug your evening macros instead of logging them.

References

  • ZXing: github.com/zxing/zxing
  • ZXing-Android-Embedded: github.com/journeyapps/zxing-android-embedded
  • OpenNutriTracker: github.com/simonoppowa/OpenNutriTracker
  • Waistline: github.com/amoses4288/waistline
  • Methodology: /methodology/