work · 2026-09-13

kaloro · design, Swift, backend, store

A photo can't see the oil

Vision models undercount home cooking by 20 to 50 percent. The fix is not a better model but an interface that shows its assumptions and lets you correct them in one tap: cooking-oil and portion chips.

SwiftUIGemini VisionCloudflare WorkersRevenueCat

Problem

Photo calorie apps are good on a restaurant plate and bad on home cooking. The reason is physics, not the model: a photo cannot see the oil in the pan, the butter stirred in at the end, or how big the plate is. A 900-calorie meal gets logged as 400 all the time. Reading competitors' one-star reviews gave three themes: wrong counts, no Turkish, a long quiz ending in a surprise charge.

Decisions

  • Show the assumption, make the fix one tap. Every result says "1 plate, about 400 g, normal oil". Two chips: cooking (light, normal, generous oil) and portion (small, normal, large). The number updates as you tap. An estimate whose assumptions are visible can be fixed; a bare number can only be wrong.
  • Photos are never stored. The image goes through a Cloudflare Worker to Gemini, the result comes back, the image is discarded in the same request. No database, no log. That also made the privacy policy short.
  • Turkish food by name. Mercimek is mercimek, not "red lentil soup". An accuracy gate with real meal photos and a reference table measured a 19-point gap on Turkish dishes.
  • Guardrails. No target below 1,200 kcal for women or 1,500 for men; nothing faster than 0.75 kg a week; no goal weight under a healthy BMI. Rated 17+; under-18s are blocked in onboarding.
  • The paywall can be closed. One free scan, price shown up front. The competitors' most frequent complaint does not apply.

Outcome

Released on 11 September 2026; 1.0.1 added the Turkish interface. Funnel counters f_scan_fix (did the user actually correct a chip) and f_trial_q (is the trial qualified) are in the code; they get to speak before any ad budget does.

What I learned a day after launch: the App Store autocorrects "kaloro" to "Koloro", an established preset app, and we do not appear. I measured it (third in Türkiye and fifth in the US on the Search API), understood why (thousands of ratings against zero), opened a brand keyword campaign, put a deep link on every outbound surface, and am waiting. Even showing up for your own name is something you earn.