Inspiration

Every 43 seconds, a child under five dies of pneumonia. That was about 740,000 children in 2019 (WHO).

The first test a health worker uses is simple: count the child's breaths for one full minute and compare the count with a cut-off for their age. People are bad at it. In a four-country trial, only 8 to 20% of health-worker counts on infants under two months were within two breaths of the true rate (Baker et al., 2019).

Every breath-counting app I found still asks you to tap the screen once per breath. Automated counters are separate hardware. Meanwhile the parent and the health worker already carry a camera.

So I asked: what if the phone could just watch the chest and count?

What it does

Breathwise turns any phone camera into a contactless breath counter that follows the WHO method.

  • 📷 Point, don't touch. Aim the phone at a sleeping or calm child. Breathwise finds the breathing by itself and highlights the chest in green tiles as it locks on.
  • 🫁 Every breath, live. A dot lands on the breathing trace and the phone gives a small vibration for each breath.
  • ⏱️ The WHO minute. It counts 60 seconds of clean signal. If the child moves, the clock pauses instead of counting noise.
  • 🩺 A clear answer. It applies the WHO IMCI fast-breathing cut-off for the child's age (≥60, ≥50 or ≥40 per minute) and walks through the IMCI danger signs. Any danger sign turns the result into "Seek care now."
  • ✋ Human backup. A tap-count mode (the manual WHO method), plus a "tap along" check against the camera.
  • 🌍 Built for the field. Spoken guidance, five languages (English, Français, Español, Kiswahili, አማርኛ) and a dark screen that won't wake the child.
  • 🔒 Private by design. No account. Video never leaves the phone and is never saved.

How I built it

Stack: Expo SDK 57 · React Native 0.86 · VisionCamera 5 (frame output + worklets) · Skia · Reanimated 4 · RevenueCat

The breathing detector is classic signal processing running on the phone in real time. There is no ML model, no server and no training data of children.

  1. Pixels → 192 numbers. On the camera thread, each frame is shrunk to a 12×16 grid of brightness averages and then released. The video never reaches JavaScript.
  2. Keep only breathing. Slow exposure drift is divided out, whole-scene movement is detected, and every cell is band-pass filtered to 8–108 breaths/min.
  3. Cells vote. Every second, each cell's spectrum is computed. Rhythmic cells vote on a rate, with a check against counting a harmonic of the real rhythm.
  4. One clean trace. The cells that agree are merged with principal component analysis, which also lines up cells that brighten and darken in opposite directions.
  5. Count like a clinician. A peak tracker counts breaths. The final result checks the count against the spectral rate and the breath-to-breath rate to report a confidence level.

Validation: 13 end-to-end tests render synthetic scenes pixel by pixel and run them through the exact app pipeline.

  • ✅ 14 to 75 breaths/min, all within ±2
  • ✅ Chest motion under one pixel
  • ✅ Heavy low-light sensor noise
  • ✅ Bumped mid-count: the clock pauses and recovers
  • ✅ No breathing at all: never locks on

Monetization with RevenueCat

Counting is free. Forever. The core breath count is never behind a paywall, and health-worker mode is free for life.

Breathwise Family (one entitlement, monthly or yearly, with a 7-day free trial) is for parents on a sick night:

  • Unlimited children
  • Breathing trends over time
  • A PDF report for the doctor
  • Sick-night recheck reminders

Every Family plan keeps Breathwise free for community health workers. The people who can pay fund the people who can't.

Built with react-native-purchases: a custom paywall built from Offerings, entitlement-gated features, restore, and Customer Center for self-service management. Tested end to end with RevenueCat Test Store.

Challenges I ran into

The core problem is finding a chest that moves one or two pixels under sensor noise, auto-exposure and hand shake. Four fixes made it work:

  • Lock the camera. Exposure, focus and white balance are frozen once the shot is framed, so auto-adjustments can't look like breathing.
  • Normalize slowly. Correcting brightness frame by frame leaked the breathing rhythm into every cell. A slow running average fixed it.
  • Respect irregular breathing. Infants don't breathe like metronomes, so the rhythm window scales with the rate.
  • Fail honestly. The detector refuses to lock when nothing is breathing, and tap mode is one tap away.

Accomplishments I'm proud of

  • A working contactless breath counter in pure TypeScript signal processing, fast enough for the camera thread.
  • A result screen that shows its work: the WHO cut-off, danger signs, a confidence level and the raw 60-second breathing trace.
  • A business model with a conscience: the core feature is free forever.

What I learned

Following the clinical protocol beats adding features. Following the WHO protocol exactly (60 seconds, pause on movement, age cut-offs, danger signs) made Breathwise clearer and more trustworthy than any extra feature did.

What's next

  • 🏥 A clinical agreement study against expert video-panel counts
  • 📴 Offline health-worker mode with supervisor sync
  • 🤖 Android tuning
  • 🤝 Partnerships with community health programs

Demo note: the measurement footage was recorded in the iOS Simulator with a simulated baby, because the Simulator has no camera. On a phone, Breathwise uses the live camera. Music: "A Kind of Hope" by Scott Buckley, CC BY 4.0. Not a medical device. Breathwise counts breaths using WHO guidance; it does not diagnose.

Built With

Share this project:

Updates

Submission history