-
-
Better Yoga — one doable plan a day. Rest days count.
-
One plan, not a library — and it tells you why: you said low energy + tight lower back, so today is gentle.
-
The morning check-in: three questions, thirty seconds. Today's plan is built from how you actually feel.
-
Guided minute by minute — calm cues, a timer, and the next move always known.
-
Rest is part of the plan. Say you're depleted and rest is logged as done — no streak lost, nothing to make up.
-
It learns you: how today felt tunes tomorrow's session.
Inspiration
The reason people quit home Pilates isn't laziness — it's that their last app punished them for being human. Streaks, guilt banners, 200-class libraries to scroll at 6am. The churn driver in home fitness isn't friction; it's guilt. We built the opposite.
What it does
Better Yoga kills the content library. Every morning a 3-tap check-in — energy · soreness · time — rebuilds exactly one doable Pilates/yoga plan for today: 5 to 25 minutes, with a plain-language rationale ("you are rested, today is 10 minutes of real work"). Say you're exhausted, sore, with ten minutes, and the session gentles itself. Say you're strong with twenty-five, and it meets you there.
And when the right plan is rest, the app writes rest into the plan and counts it as done. No streaks to lose, no countdown paywalls, no body-transformation promises. The rest-day notification congratulates you for not opening the app.
How we built it
Flutter (Android + iOS) · Firebase Auth/Firestore (one uid = single identity across web + app) · RevenueCat for subscriptions, plus a web checkout funnel at better-yoga.app (Stripe) with promo-code support · OneSignal for lifecycle messaging — 3 Journeys, 2 in-app messages, entirely tag-driven: the whole web-funnel and subscription lifecycle runs on tags with zero backend code · Layers for the growth loop — owned social automation on TikTok + Instagram and SDK measurement (27 event types streaming, RevenueCat + Stripe revenue webhooks, a published tracked-link bio page).
The design rule that shapes the messaging architecture: local handles what the device knows; OneSignal handles the relationship. Daily plan reminders and the rest-day companion are local notifications, because the device already knows. OneSignal owns what it can't know alone: lifecycle, lapse, subscription state, the web funnel.
Challenges we ran into
An honest list. Our OneSignal win-back journey for cancelled subscribers was architecturally sound and permanently entrant-less — a pre-revenue app has nobody to win back — so we specced its replacement — a First-Session Activation journey aimed at the ~22 real users stuck between install and first session, its plan-rationale push templates already shipped through the OneSignal API — and covered the win-back moment with an in-app message instead. Our first content experiment had a variance problem: 14 of 15 posts accidentally tested the same message, so we re-fielded all three pre-registered arms in one day through Layers. And we learned the hard way to verify every AI-generated link against a real dashboard before shipping it.
Accomplishments that we're proud of
- A lifecycle system where no user can be double-messaged by two schedulers — journey audiences are disjoint by lifecycle state, push days are offset by design, and quiet hours (8:00–20:00, the user's own timezone) are structural, not aspirational.
- A win-back that ends in deliberate silence — the last message promises to stop nudging, and does.
- A pre-registered growth experiment (hypothesis and kill thresholds written before any post went live) running entirely inside Layers: auto-generate → approve → post → measure, 80+ posts shipped — and when the verdict came in, the hypothesis was falsified and we said so: humor out-pulls tenderness on cold traffic, so the rest-positive voice moved to retention push copy, exactly as the pre-registered alternative specified.
- Personalised pushes that quote the user's own plan rationale back to them via tags — the most literal "value to the user" personalisation we could build.
What we learned
Distribution discriminates more than hooks. Honest zeroes (saves, MRR) reported early beat flattering vagueness. Constraint-driven design — a 3-journey plan limit, a segment cap — reads as a budget deliberately spent, and produces cleaner systems than unlimited plans would have.
What's next
Experiment 2 is specced and pre-registered: an in-product share card fired on session completion — workout variant ("12 gentle minutes. Done.") vs rest variant ("Today's plan was rest. I took it. ✓"). Hypothesis: rest cards out-share workout cards, because pride in permission is rarer than pride in effort. That closes the loop: content in → funnel → product → share card → content back out.
For the OneSignal "Keep Them Coming Back" award
Three surfaces, each doing a different job. Journeys: Onboarding (D1–D7 activation drip, 51 in / 20 completed), Re-engagement (a lapsed-user win-back that ends in tagged silence, 65 in), and a RevenueCat-tag-driven cancelled-subscription win-back — honestly entrant-less pre-revenue; its successor, a First-Session Activation journey that pushes each user's own plan_rationale tag as copy, is specced with both push templates already created through the OneSignal API. In-app messages: a win-back offer card for RC-expired subscribers and a gentle upgrade card — both zero-urgency, with "Maybe later 🤍" styled as prominently as the CTA. Guardrails: every send passes a per-user-timezone time window; pacing is enforced by journey structure. The entire subscription lifecycle is driven by RevenueCat → OneSignal tags with no server. API-verified audience at submission: 57 subscriptions, 35 actively push-subscribed (≈78% device opt-in), 12 email subscriptions. OneSignal App ID: cccf74f5-4811-4faa-889d-751ed9995608.
For the Layers "Growth Loop" award
Layers runs the entire owned-content operation: TikTok @better.yoga ("June") and Instagram better.yoga.app ("Clara"), auto-generate → approve → post, all three content formats, 80+ posts shipped, plus a published Layers bio page with a tracked Get Started store link. The loop is measured inside Layers itself — 27 SDK event types from install to upgrade-click, RevenueCat + Stripe revenue webhooks. The experiment was pre-registered (Aug 12, before any post): rest-positive messaging (B) will out-convert demo content (C), because this audience churned from guilt, not friction. The verdict (Sep 18 read, 65 experiment posts): falsified — A (relatable-pain humor) 1.54 saves/1K · B (rest-positive) 0.42 · C (demo) 2.17. B landed at ≈0.27× A, nowhere near the pre-registered 2× bar, so B became the retention voice in push copy — exactly the pre-registered alternative — while the demo arm the hypothesis said would lose earns the most saves per view and now shapes the acquisition hooks. Day-1 numbers were unflattering and reported anyway; a pre-registered hypothesis that can die in public is the loop working. Layers project: 528ec545-f758-4ff4-ad63-3837af90a079.
For the Influencer Award — Yoga
Personalisation that respects the body in front of it; rest days that count; restraint as deliberate design — no weight-loss promises, no fake counters, no countdown timers, a cancel link inside our own retention emails. Try it the way a user would: install fresh, answer the check-in honestly on a low-energy day, watch the plan shrink to fit you, skip tomorrow entirely, and notice that nothing shames you when you come back. The brand persona is an original AI character — no real-influencer likeness anywhere.
IDs for judges: RevenueCat project Better Yoga · 5c9b2c1c · Web funnel: https://better-yoga.app · TikTok @better.yoga · Instagram better.yoga.app
Log in or sign up for Devpost to join the conversation.