Skip to content
← Projects

Case study

Thunai: a habit tracker and its retention problem

Built and shipped solo in one week. 102 signups. 58 people logged a habit. Only 11 ever came back for a second day.

The longest streak any user has ever achieved is one day: the streaks, the freezes, the evolving pet, the entire mechanic the product was built around have never once activated in the wild. This page is about why.

  • 102

    signups

  • 58

    logged a habit

  • 11

    came back for a second day

  • 1 day

    longest streak, ever

The idea

I built this during end-term exams. My sleep, food and study habits were the first things to go under stress, and most habit trackers are checklists. A checklist gives you nothing for showing up. My bet was that a virtual pet that only grows when you do creates enough emotional cost to breaking a streak that people keep logging.

One week from idea to live PWA, solo, alongside exams.

Four screens of the Thunai app: the leaderboard, logging yesterday's habits, today's habits with the pet, and how the pet grows

What actually happened

StageUsersRate
Signed up, created a pet102n/a
Logged at least one habit5857%
Logged on a second day1110.8%
Active in the last 7 days3~3%

Median days survived is zero: for the typical user, first log and last log were the same day. 77.6% of everyone who logged anything was gone inside twenty-four hours. Day-1 retention was 4.9%. By day 14, across 97 eligible users, it was zero.

Line chart of the percentage of signups active on day 1, 3, 7, 14 and 30: 4.9%, 2.1%, 3.1%, 0% and 1.1%

This is a cliff, not a bleed. Activation was never the problem: more than half of signups did the thing the product asked. The failure is first session to second session, and everything downstream is a consequence, not a cause.

Where it broke

Nobody ever enabled notifications. Not one person.

The obvious read is that the feature was broken or the ask was badly designed. It wasn't. The permission flow is correctly gated: it waits until a user has logged a habit, then asks explicitly. On iOS Safari it doesn't fire at all unless the app has been installed to the home screen, which is Apple's constraint, not mine.

The actual reason is timing. Notifications shipped 13 days after the app did. By then, 72 of 102 signups already existed, and only 4 of those were still logging. The maximum reachable audience for my retention feature, on the day it launched, was four people.

I built the reason to return after the window to return had closed.

The feature I stopped building

I also started a weekly email report: what you did well, what to improve, insights from your own data. Getting there meant a Brevo account, a dedicated sending address, and buying a domain.

The code is finished. The configuration never happened: the stats table was never migrated, the API keys were never set, and the whole thing exists in a single commit that is also the last commit in the repo.

I stopped because the potential audience was five users. Spending a weekend building retention for people who had already left was the wrong trade, and killing it was right.

But the reason I was in that position is the actual lesson. Both of my retention mechanics, notifications and weekly reports, were scheduled after launch. The product shipped with all the delight up front and every reason to return behind it. Sequencing retention behind acquisition is the mistake; the individual features are a symptom.

What the data killed

The crowded-leaderboard theory. I assumed late joiners saw an uncatchable list and disengaged. Across the two cohorts large enough to trust (n=74), there was no meaningful difference. Dropped. A better design might still give each user their own scoreboard, starting from the day they create a pet and ranking who has logged the most habits since then.

Streak freeze. Used by exactly one person, ever: a feature built for a failure mode nobody survived long enough to hit.

Pet choice as a retention driver. No correlation between which pet a user picked and how long they lasted. Worth being precise about what that does and doesn't mean: it says choice of pet doesn't predict survival. It doesn't say pets were worthless. Users told me directly that they liked the pets and the sounds, and pets are plausibly why 58 people logged anything at all. I'm keeping them. The data constrains one specific claim, not the whole design.

What I got wrong about my own users

43% of signups created a pet and never logged a single habit, and 93% of those never returned.

Their signup timestamps cluster tightly around 11 AM and 3 PM, the minutes after I sent WhatsApp messages asking people to try it. Almost all of my users arrived in a burst from a direct ask, not from finding the product. Signing up as a favour and signing up because you want the thing are different intents, and I'd been reading the funnel as though they were the same.

That matters for what comes next: a win-back message to someone who never wanted the product isn't retention work, it's noise.

Including me

I stopped using Thunai during a heavy term, the conditions it was built for. My habits slipped and the app became one more thing to face rather than the thing that helped.

That's a product failure, not a user failure. A habit product that only works when you're already doing well has inverted its own premise. Designing for the bad week rather than the good one is the constraint I'd build v2 around.

What I'd do next

Fix the return trigger, and fix it first. Nothing else matters until a user can be reliably reached on day 2. That means the permission ask ships with the product, not after it, and iOS users get an install prompt that explains what installing buys them.

Instrument before launching. Then run one small, properly tracked cohort to isolate whether the day-2 gap is friction or motivation. The current dataset can't separate those, and no additional query will.

Keep the pets. They're the only part of the product users volunteered praise for unprompted.

What I'd do differently on the build

I shipped with no instrumentation. No analytics library, no event log, no device or browser capture. I reconstructed this entire funnel from raw tables afterwards, and I still can't tell you what devices my users were on. I could see that people left; I had to infer where.

I let a failure path stay silent. When the app saved a notification preference, it never checked whether the save succeeded: on a server error it still displayed “✅ Reminder set” and marked the user as done, with no retry. A failed save was indistinguishable from a working one, to the user and to me. Given that nobody got that far, it cost nothing here. It's the kind of thing that costs a lot elsewhere.

The idea and the product bet were mine. Claude Code was the implementation layer, and I used Claude to pressure-test some of the decisions along the way.

Stack: Vanilla JS, HTML and CSS · Supabase (Postgres, custom PIN auth, leaderboard) · Web Push API · Brevo · deployed as a PWA on Vercel.

Open question

Does a habit product work better as a companion you tend, or as an instrument you check? Thunai bet on the first, and the pets suggest the bet wasn't wrong. But I never got far enough into the loop to test it: the next version has to earn day 2 before it's allowed to be clever.