-
-
this is the home/landing page
-
the profile page to access/edit personal details, subscribe to pro and change the appearance
-
the calendar page to keep an eye on the performance
-
all groups listed
-
this i show a group looks like
-
here's the friends' list
-
adding a new habit looks like this
-
habit details screen
-
gatekeeping pro features
-
Trackly logo
Trackly — A Social Habit Tracker Built for Accountability
The Problem: Accountability Without the App
My girlfriend and I weren't trying to change our lives. We just wanted to work out consistently instead of restarting every few weeks like usual.
The habit tracker ecosystem is full of apps that do the basics well: create a habit, check it off daily, watch your streak climb. But they're all built around a single assumption: you're doing this alone. I could see my own progress in vivid detail. I had no idea if she'd worked out yesterday. If she hit snooze and skipped a day, I'd only find out when she told me. We were trying to build a habit together, but the apps had no concept of "together."
That's a small gap, but it matters in a way I didn't fully appreciate until trying to close it: knowing someone else showed up that day is a huge part of why you show up the next day. Isolation kills consistency. Every tracker I tried solved it with a half-hearted friends list or a shared leaderboard that felt bolted on as an afterthought.
That frustration became the seed for Trackly.
What It Actually Does
Trackly is a social habit tracker where accountability is the core feature, not an add-on.
You create habits—"morning run," "read 30 min," "study JavaScript"—and mark them complete just like in any other tracker. You get streaks, progress views, calendar histories. But it's structured around a different question: How am I doing alongside the people building this with me?
Instead of tracking your habit in isolation and then bolting on a social layer, Trackly flips the model. When you log a habit completion:
- For individual habits: Only you see the completion. Your streak. Your progress.
- For shared tasks: You and the people you invited both see the same habit. Two separate streaks, one shared leaderboard so you can see how you're tracking against each other.
- For group challenges: Up to N people in a group, competing toward a shared weekly target. Quantified (run 5km, drink 8 glasses of water) or simple (practice piano 30 min). Real-time leaderboards.
The accountability isn't a separate feature you unlock—it's baked into how the app is structured from the data layer up. That distinction shaped almost every technical decision.
How I Built It (and Why It Got Complicated)
Stack:
- Frontend: Flutter (single codebase → iOS, Android, Web)
- Backend: Firebase (Firestore, Auth, Cloud Functions for push notifications)
- Real-time sync: Firestore listeners + Provider state management
- Monetization: RevenueCat integration for premium subscription flow
The simplest version would've been: store habits in Firestore, each user sees their own. Simple.
But the moment a second person joins a habit, everything gets harder.
The Sync Problem
When you mark a shared habit complete, that single action now touches multiple pieces of state across multiple devices:
- Your personal streak for that habit
- Your friend's leaderboard view (showing your completion)
- The shared progress graph for that habit
- Push notifications to your friend saying "they just completed it"
If you're not careful, one of these updates goes stale while another succeeds. Your friend sees you completed it, but the leaderboard doesn't update. You see a streak increase, but the shared view hasn't caught up.
The solution: Real-time Firestore listeners. Every Habit/Group is stored as a document with a completions map:
Map<String, List<DateTime>> completions; // { "uid1": [DateTime, DateTime...], "uid2": [...] }
This structure is the secret. Instead of separate records per user, completions live in one document. When you toggle a habit complete, you:
- Optimistically update your local UI immediately (feels instant)
- Fire a single write to that document with your updated completion list
- The Firestore listener on every participant's phone fires automatically, syncing everyone to ground truth
No coordination logic. No eventual consistency bugs. One source of truth, streamed to all participants in real-time.
Calculating Streaks at Scale
Once multiple people are involved, the streak logic can't just be "days in a row." It needs to answer:
- What's your streak on this shared habit?
- What's their streak on the same habit?
- How many consecutive days did you both complete it? (for accountability metrics)
For each participant, I calculate currentStreakFor(userId) by:
- Pulling their completion dates for that habit
- Sorting chronologically
- Checking each date: is it consecutive from today (or yesterday if today isn't done)?
- Stopping at the first gap
Sounds simple. It took iteration to get right because off-by-one errors in date comparison means your 12-day streak suddenly shows as 3. That kind of bug tanks the core motivation mechanic of the app.
Multi-Participant State Management
I use Provider (Flutter's go-to state management for real-time apps). Each Habit/Group streams from Firestore via HabitsProvider:
Stream<List<Habit>> streamHabits() {
return _db
.collection('habits')
.where('participants', arrayContains: currentUserId)
.snapshots()
.map((snapshot) => snapshot.docs
.map((doc) => Habit.fromMap(doc.data(), id: doc.id))
.toList()
);
}
The where('participants', arrayContains: currentUserId) query means Firestore only sends documents relevant to you. Combined with persistent caching enabled client-side (persistenceEnabled: true, cacheSizeBytes: UNLIMITED), the app works offline and syncs when you come back online.
When you toggle a habit completion, the optimistic update fires immediately (good UX), the server write happens in the background, and the Firestore listener reconciles everyone's state automatically. If there's a conflict (you toggled while offline, then came back online), Firestore's last-write-wins semantics resolve it. In practice, this is fine for habit completion—you're unlikely to have genuine conflicts on whether you worked out today.
Groups and Quantified Challenges
Beyond shared habits, groups are first-class citizens:
- Group tasks: Shared to-dos (e.g., "team book club, read chapter 5")
- Group challenges: Weekly quantified goals (e.g., "group of 5, 50km running total this week")
Each group has nested Firestore collections:
groups/{groupId}/tasks/{taskId}
groups/{groupId}/challenges/{challengeId}
Members can join via invite, see live leaderboards, log daily progress toward the challenge target. The challenge leaderboard updates in real time as members log progress.
The Hard Part: Making "Social" Meaningful
The technical challenges were solvable with time. The product challenge was harder.
It would've been easy to add a friends list and ship it. Easy to copy Strava's leaderboard UI. Easy to slap on a comment section.
But none of that would've helped with accountability. It would've just added clutter.
I kept asking: Does this feature actually make someone more likely to show up tomorrow?
- Friends list? Not by itself, no. But invite-to-habit? Yes—now you're explicitly saying "I want you to track this with me."
- Weekly leaderboard on a shared habit? Yes—you can see if they're keeping pace.
- Comments on completion? No—that's noise. Nobody reads them. Deleted it.
- Achievements? Helpful as confirmation. Kept them.
- Weekly report to your friend? Helpful as a prompt to check in. Added it.
This question—"does it actually help accountability?"—filtered way more ideas than the technical constraints did.
The RevenueCat Integration (Test Setup)
For monetization, Trackly includes a full subscription flow powered by RevenueCat (v10.4.1). Currently running on RevenueCat's test store for this contest build, but the production logic is identical:
- Premium unlocks: Groups, quantified challenges, analytics, mood tracking
- Non-blocking async init: RevenueCat is configured on app start without blocking the UI
- Entitlement checks: Each premium feature gates itself via
subscriptionProvider.hasProAccess - Purchase flow: Full RevenueCat paywall sheet for upgrade
The test paywall is functional. In production, it'd point to App Store / Play Store subscriptions.
What I'm Proud Of
I solved a real problem I had: I couldn't find a habit tracker that actually understood "we're doing this together." So I built it—from product thinking through design through implementation to a working app.
Technically:
- Real-time sync across multiple participants without eventual consistency bugs
- Streak calculation that's correct for shared vs. individual contexts
- Multi-participant state management that keeps UI snappy even with frequent updates
- Groups + quantified challenges on top of shared habits
- RevenueCat integration wired through the entire feature set
- Cross-platform Flutter codebase (iOS + Android + Web from one codebase)
- Firestore security rules covering every collection and action
- Push notification infrastructure (FCM) with invite/response tracking
Product-wise:
- Accountability built into the core, not bolted on
- Every feature exists because it helps people stay consistent, not because it's technically doable
- Invitation flow that makes it explicit: "I want to build this habit with you"
- Leaderboards and progress views designed around shared context, not isolation
Technical Learnings
Real-time sync is harder than it looks. Getting state aligned across devices requires discipline: single source of truth in the database, listeners on every client, optimistic updates with reconciliation. One bug in this layer breaks the core feature.
Streak calculation is more subtle than just counting days. Off-by-one errors in date comparison, timezone handling, "did today count?" logic—all of it matters because streaks are the core motivation mechanic.
Groups scale complexity exponentially. One person: simple. Two people on a habit: real-time sync required. Groups of 5+ on quantified challenges: now you need leaderboards, weekly rollup logic, member-defined vs. shared task modes. I ended up with separate GroupService, GroupTask, and GroupChallenge models to handle it.
Multi-platform Flutter is a superpower. Building native iOS + Android separately would've doubled the time. Flutter let me focus on the core product and ship everywhere.
What's Next
The immediate next step is getting Trackly on the App Store and Google Play with RevenueCat running as a live production paywall instead of the test store setup.
Beyond that, the focus stays on accountability:
- Better ways to feel connected to someone else's progress (not just a number next to their name)
- Weekly group summaries: "Here's how we did together"
- Optional public groups: build a habit with randos, see their streaks too
- Integration with health platforms (Apple Health, Google Fit) for auto-logging
- AI-powered peer verification: "Did you really run 5km? Validate with a photo"
The goal isn't more features for the sake of it. It's making Trackly the habit tracker people reach for because they're not trying to do this alone. That was the original gap. That's still the one that matters most.
Why This Matters
Habit trackers are common. Habit success is rare. The difference isn't the app—it's accountability. Most trackers ignore this entirely. Trackly doesn't. It's built around the specific context of "I'm building this with someone else," not bolted on after the fact.
That distinction is the entire product.
What started as frustration at not finding what I wanted became a working app that my girlfriend and I actually use, with a subscription model, a functioning premium layer, and the infrastructure to scale to groups of any size.
Trackly is proof that you don't need a network of millions to make social features meaningful. You just need to ask whether they actually help people stay consistent—and have the discipline to say no to everything else.


Log in or sign up for Devpost to join the conversation.