Inspiration

Running in a group keeps people consistent. The hard part is getting everyone to the same place at the same time, and that is where most run clubs fall apart. We wanted a club's accountability without the scheduling, so we built teams that run asynchronously. Your phone logs your runs, and your five teammates follow your progress on their own time.

The idea rests on Irwin, Feltz et al.'s 2012 study of the Köhler effect (Ann Behav Med). People exercised significantly longer when they believed the team's result depended on its weakest member. Groups are capped at six, so a skipped run is easy to see, and nobody wants to be the one who let the team down.

The psychology we built on

Intergroup competition. A global leaderboard stops motivating people once they realize they'll never reach the top. We set small teams against each other in two-week seasons instead. The short season gives a clear finish line and a quick reset if one goes badly. Team loyalty gets people out on days they'd normally skip.

Loss aversion and turf. We split the real world into H3 hex cells that players claim by running through them. A nightly job decays cells nobody is defending, so rivals can take them. Prospect theory puts the cost of a loss at roughly twice the pleasure of an equal gain:

$$v(x) = \begin{cases} x^{\alpha} & x \ge 0 \ -\lambda(-x)^{\beta} & x \lt 0 \end{cases} \qquad \lambda \approx 2.25$$

(Tversky & Kahneman, 1992.) Watching your map shrink is a strong reason to go back out.

Social dating and the bounty. Men can post an optional bounty, bought in-app through RevenueCat, to be guaranteed a mixed group of three men and three women. Half of it funds the platform. The other half is held in escrow and paid out at the end of the season to the women who qualify. Entering a season stays free for everyone. The bounty does two jobs. Wanting to impress the group raises the stakes the Köhler effect already depends on, and women get a concrete reason to stay active for the full two weeks. Payouts aren't competitive, so they can't be farmed. Every woman who clears a hidden bar on distance and frequency gets the same flat amount, and running past the bar earns nothing extra.

How we built it

  • Frontend: one React Native / Expo codebase for iOS (built through EAS) and Android.
  • Payments: the RevenueCat SDK sells the bounty as a one-time purchase; a RevenueCat webhook records it against the runner's season entry, idempotently, and reverses it on refund.
  • Backend and database: FastAPI with async SQLAlchemy on PostgreSQL, hosted on Railway.
  • Mapping: Uber's H3 grid. Cells are stored as plain text IDs, so we didn't need PostGIS.
  • Automation: Python cron jobs run the nightly territory decay and an hourly leaderboard rollup.
  • Auth: Sign in with Apple with JWTs.
  • Testing: an offline script, simulate_turf.py, tests scoring rules before they reach real runners.

Challenges

At first, cell ownership was winner-takes-all, so a runner who came a close second across a whole neighbourhood scored zero. That was too discouraging, so we added an influence score. It credits a runner for every cell where they have any live score, and the leaderboard ranks by its 30-day moving average.

Averages caused a different problem in our orientation season for Singapore schools. Ranking schools by average turf per runner meant every new member pulled their school's score down, and one strong solo runner couldn't be beaten. We switched to total turf held, which rewards schools for bringing people in.

Seasons used to charge an entry fee. Entry is now free and automatic: a run logged inside an open season enters you. The only thing for sale is the bounty.

What we learned

Stay strictly within what the behavioral science supports. We don't claim the well-known "rowers' high," for example, because that bonding effect requires moving in sync, in person, and async running can't provide it. Every claim the app makes comes from one sourced file, and we cut any feature we couldn't tie to one of our five motivation levers.

Built With

Share this project:

Updates

Submission history