Streaks

Role
Design & engineering (solo)
Year
2026
Stack
SwiftUI · Firestore · Functions · FCM

Streaks started with a simple question: what if a habit tracker asked for proof instead of a checkmark? A photo does more than confirm that something happened. It lets you see the habit changing over time.

The first build was tiny: create a tracker, post one photo a day, keep the streak alive. Then I put it in front of friends, watched the model break, and rebuilt around what they expected to happen.

Starting point

Replacing the checkmark

The first version was deliberately narrow: a personal tracker where the main action was taking a photo. The streak still mattered, but the archive mattered more. It turned progress into something visible.

That changed the product questions. Posting had to feel fast. The archive had to be worth opening again. Some habits only needed a visual log; others needed a place boundary or a bit of pressure from friends.

Version one
First welcome screen
First welcome screen
Early calendar view
Early calendar view
Early tracker archive
Early tracker archive
Location gating

For habits tied to a place, Streaks can require the user to be there before logging progress. It turns intention into a small boundary: gym trackers at the gym, studio trackers at the studio, and fewer fake wins.

Searching for a required place
Searching for a required place
Setting the boundary
Setting the boundary
Blocked outside the location
Blocked outside the location
Shared tracker flow

Once photos became the core action, shared habits started to feel natural. A workout tracker could become a small group space where friends post progress into the same streak instead of maintaining separate counters.

That meant adding just enough group machinery for the tracker to feel shared without turning it noisy.

Shared tracker overview
Shared tracker overview
Finding people to invite
Finding people to invite
Selected friends
Selected friends
Invite link and QR code
Invite link and QR code
People tab
People tab
Member actions
Member actions
Tracker settings
Tracker settings
Group highlights
Group highlights
Shared tracker overview
Shared tracker overview
Finding people to invite
Finding people to invite
Selected friends
Selected friends
Invite link and QR code
Invite link and QR code
People tab
People tab
Member actions
Member actions
Tracker settings
Tracker settings
Group highlights
Group highlights
First users

The early app had two modes: local trackers for quick solo use, and shared trackers that required an account. It looked like a good tradeoff until people started using it.

The first signal came from a close group of about eight testers. A few created local trackers, deleted the app, reinstalled it, and expected their progress to come back.

The bug report was simple, but the product problem was bigger: if a tracker had no user id, there was nothing to reconnect. Continuity could not be treated like an advanced feature in a habit app. It was the product.

Model shift

The restore problem pushed Streaks away from local trackers and toward account-backed continuity.

Old model

  1. Create trackerNo sign-in required
  2. Save locallyOnly inside app storage
  3. Delete appLocal copy is wiped
  4. No restoreNo account ever existed

New model

  1. Sign in with phoneCreates a permanent user id
  2. Create trackerTied to that account
  3. Reinstall appSign in again
  4. Progress restoredSynced from the cloud

Protecting existing history

Changing the model also meant writing a migration path for people already using local trackers. When they opened the new version, Streaks uploaded their existing trackers, photos, and wallpapers into the account-backed system before letting them continue.

One migration run had 64 local items to sync. That was the useful number: the old model already held real history, so the rebuild had to preserve it.

Local streak history syncing into the new account-backed model
Local streak history syncing into the new account-backed model
Where the work went

A rough split of the six-month build. Most of the time went into changing the product model without losing the thing people had already trusted the app with: their history.

  • Product model + rebuild30%moving from local/shared to account-backed trackers
  • Core iOS flows25%posting, archives, and tracker details
  • Shared trackers + invites20%member flows and invite links
  • Location gating10%place search and blocked states
  • Landing + App Store surface10%web motion and screenshots
  • Polish + tester feedback5%small fixes, edge cases, release cleanup
Landing page phases

The landing page changed as the app changed: from a simple App Store page to a more visual surface that carried the feeling of Streaks.

Rebuild

Making every tracker durable

I rebuilt the product around continuity. Streaks moved from a local/shared split to an online-first model where every tracker belongs to an account. Shared now simply means more than one member, not a separate kind of tracker.

I also simplified onboarding. The old flow asked for email sign-in, then a phone number. The new flow starts with phone verification and only asks for profile details after that. It is less anonymous at the start, but much safer for a product built around history.

The backend had to support that calmness too. Shared photos wait for moderation, notifications are debounced, shared trackers sync quietly, and uploads can recover when storage finishes before Firestore does. The current product is still photo-first, but the system around it is clearer and easier to extend.

Product showcase
Current tracker view
Current tracker view
Photo cutouts
Share card
Share card
Image tap ripple
Lock Screen recap
Lock Screen recap
Invite milestone
Phone-first onboarding
Phone-first onboarding
Tracker archive export
Tracker archive export
Compact widget
Compact widget
QR contact card
QR contact card
Recap reel
Recap reel
Current tracker view
Current tracker view
Photo cutouts
Share card
Share card
Image tap ripple
Lock Screen recap
Lock Screen recap
Invite milestone
Phone-first onboarding
Phone-first onboarding
Tracker archive export
Tracker archive export
Compact widget
Compact widget
QR contact card
QR contact card
Recap reel
Recap reel
Next

The next thing I want to measure is whether shared trackers actually improve return rate, not just whether they make the app feel more alive. Streaks is stronger now, but the product still has to learn which habits need pressure, which ones only need a record, and when the app should stay quiet.

Links & credits