Inspiration
Every alarm clock has the same flaw: a button that lets you lie.
We'd set a 6:00 alarm to run, tap Stop, and go back to sleep. We'd sit down to study, put the phone face down, and pick it up "for a second" forty minutes later. Habit apps didn't help. They ask you to tick a box, and a box can't tell whether you did the thing.
So we asked a different question: what if the alarm didn't stop until your phone could tell you'd actually shown up? No done button. No snooze-and-forget. Just proof.
Research backed the idea that friction works. A short pause before opening a distracting app cut app opens by 57% over six weeks (Grüning et al., PNAS 2023). ShowdUp turns that friction into proof.
What it does
ShowdUp is an Android alarm you have to show up for. You pick a time window and what showing up means. Then it rings, and keeps coming back, until your phone can tell you did it.
Setup starts with why you're here: Study or focus, Move or run, or Wake up. Each one shows only the proofs that fit it, and every proof says in one line how it's checked:
- Phone-down focus: the apps you pick (for most of our testers, Instagram) stay shut until the timer ends. Open one and you get caught: a full screen the first time, showing the reason you wrote ("Exam on Monday"). After that, a small card and Android goes home.
- Wake up with a tag: scan a code you placed away from your bed. In our demo it's the barcode on a face wash in the bathroom. Only that exact code stops the alarm.
- Run or walk: GPS distance or time. Fake locations and car speeds don't count. When you hit the goal the ringing stops, but the run keeps recording, then gives you pace, kilometre splits and your route drawn as art.
- Steps, counted by the phone's step sensor (shaking it doesn't count), and LeetCode, read from your public profile.
- Gym or a place (Pro): GPS sees you arrive and stay.
The logo is the interface. ShowdUp's mark is a dot above a cup: a person with their arms up. Turn it upside down and it's a bell. So the mark is the alarm's state:
- Ringing: the bell rocks while you're due.
- Showed up: proof lands and the bell turns over. The dot is you, standing up.
- Missed: an empty cup. No dot, and no shame.
- Couldn't tell: a dotted dot. A failed sensor never counts as a miss.
The same marks fill your History grid, with a key one tap away, next to your records: days showed up per activity, best streaks, badges and every run.
It's honest on bad days too. Hold End today and the reminders stop, recorded as an ended day, not a fake win. Missed today? Never miss twice.
Everything stays on your phone. No account, no ads, no data sold.
How we built it
- Flutter + Riverpod for the app: about 17,300 lines of Dart. It's local-first, with no sign-up, and the logic that decides whether you showed up lives in pure, unit-tested Dart classes.
- Native Kotlin (about 2,850 lines) for everything that must survive Android closing the app:
EscalatingAlarmEngine: exact alarms that keep returning inside your window, even after a reboot.TrackingService+RoutePolicy: a foreground GPS service that filters fixes, proves the run, then keeps recording until you finish.AppBlocker+CatchPolicy+CaughtFlash: an Accessibility service that reads only which app is in front, then closes it.FocusTracker: the phone-down timer, which restarts if a held app stays open.OverlayService: an optional companion bubble that floats over other apps.
- Google's code scanner for tags, so ShowdUp never needs camera permission. It stores only a scrambled fingerprint of the code.
- RevenueCat + Google Play Billing for Pro, priced per country.
- Firebase (Auth, Firestore, Cloud Functions in TypeScript with zod) for optional friend Battles, which never see your proof.
- Website on Firebase Hosting, with the APK on GitHub Releases.
The maths of an honest run
Every GPS fix passes four gates before it counts: it can't be mocked, its accuracy must be within 50 m and it must be under two minutes old, and the speed between fixes must be between 0.5 and 8 m/s, because anything faster is a car. Standing still makes GPS wander, so a new fix only counts as movement once it leaves a jitter radius around the last point:
$$ r = \max\left(5\ \text{m},\ 0.5 \times \text{reported accuracy}\right) $$
The distance between two fixes uses the haversine formula:
$$ d = 2R \arcsin\sqrt{\sin^2!\left(\frac{\Delta\varphi}{2}\right) + \cos\varphi_1 \cos\varphi_2 \, \sin^2!\left(\frac{\Delta\lambda}{2}\right)}, \qquad R = 6371\ \text{km} $$
Splits are timed at the exact moment the route crosses each kilometre. When a boundary falls between two fixes, we interpolate the crossing time from the distance on either side of it:
$$ t_k = t_a + (t_b - t_a)\,\frac{D_k - s_a}{s_b - s_a} $$
The route is drawn as a line on ink with no map tiles, so a shared run card never shows the streets where you live.
Challenges we ran into
- Proving without spying. Every proof had to be believable and private. Accessibility can read whole screens, but ours only ever reads the package name of the front app. The tag stores a fingerprint, not the code. Routes never leave the phone.
- Android fights background work. We had to handle exact-alarm permissions, foreground-service types, battery optimisation and reboots so that a 6:00 alarm really rings at 6:00, and keeps ringing.
- GPS lies. Mock locations, jitter while standing still, stale fixes and car speeds all had to be filtered before a single metre counted.
- A bug that only shows up abroad. Our early builds silently put every user on India time, so someone in London would have woken at the wrong hour. ShowdUp now follows the phone's timezone and its 12- or 24-hour clock, and shows kilometres or miles by region.
- Distribution is a policy problem. Google Play needs a declaration and demo video for Accessibility use. Play Protect blocks apps installed from outside the store that use Accessibility in some regions, including India. And Firebase's free plan refuses to host APK files, so our download moved to GitHub Releases.
Accomplishments that we're proud of
- A real, signed Android app you can install today, not a prototype. Alarms fire after the app is killed and after a reboot.
- A logo that works as a state machine. One shape tells you whether you're due, done, missed, or unsure, from the onboarding to the History grid to the website.
- Six ways to prove you showed up, none of them a button, each with a plain-language line explaining how it's checked.
- Strava-style run summaries with zero location exposure.
- 123 automated tests across Flutter, Kotlin and Cloud Functions, all passing, and zero analyzer issues.
- Ready for the world: device timezone, local clock, km or miles, and regional pricing.
What we learned
- Real users rewrite your roadmap. Our first tester ignored half the features. What stuck was locking Instagram while studying. What they asked for was Strava-like runs and badges. That one session made runs free, put an intent picker at the start of setup, and gave us records and badges.
- Trust has to be visible. The first question every tester asked was "how does it know I really did it?" Now every proof answers that in one line, right where you choose it.
- Accountability needs a dignified exit. An app that holds you to a promise must also let you off the hook honestly on a bad day. "Couldn't tell" and "Never miss twice" came from that.
- Design is behaviour. Making the mark carry meaning did more for understanding than any tutorial text.
What's next for ShowdUp
- Google Play. Closed testing first, then a public launch, so installs are one tap with no Play Protect warnings.
- Friends ranking by days showed up. The server side is already built behind a feature flag.
- More languages, and more proofs (Health Connect workouts are next).
- iOS, once the Android version has proved itself.
Log in or sign up for Devpost to join the conversation.