Inspiration

After moving to Seattle and starting a new job, my gym consistency took a hit. What got me back on track wasn't a more ambitious fitness goal. It was a friend who would notice whether I showed up.

That felt like something worth building around: two friends, a small weekly promise, and a little friendly competition. Enough to make “I'll go tomorrow” harder to get away with.

The punishment cards give each challenge its personality. Maybe the loser buys coffee. Maybe they run an extra mile. You might choose a card with your friend in mind, then end up owing it yourself.

What it does

Lock In Twin turns a weekly goal into a private challenge with one friend. Choose an activity and a weekly target that each of you aims to reach. Pick four possible punishments from the cards, write your own, or mix both. Your friend reviews the goal and all four cards before accepting. One card is drawn to set that week's punishment.

Check in with a photo taken in the app. Your friend has twelve hours to approve or reject it; unanswered check-ins automatically confirm so progress doesn't get stuck waiting.

Miss your weekly target while your friend meets it, and you do that week's punishment. If you both meet the target, or both miss it, there's no punishment for that week. It's about reaching the agreed goal, not logging more than your friend. Either person can submit punishment proof; the winner confirms completion. The result stays in your shared history.

You can keep up to three separate 1v1 deals. Creating challenges, writing your own cards, checking in, reviewing proof, and keeping history are free. There are no ads or subscriptions. If you want different stakes for a future week, turns proposing a replacement deck alternate; the agreed deck carries forward unless a replacement is accepted.

How I built it

This is my first shipped app. I built the initial version over five weeks using SwiftUI for the iPhone interface and Firebase for phone sign-in, shared data, photo storage, and notifications. TypeScript Cloud Functions enforce the agreement, check-in review, and weekly settlement rules. Firestore listeners keep both people's screens up to date.

RevenueCat powers the optional three-credit re-roll pack. The SDK loads the offering and handles the purchase; the backend verifies ownership with RevenueCat before granting credits. The immediate fulfillment call and the webhook share a transaction ledger, so a retry can't grant the same purchase twice. The app reads the server's credit balance rather than awarding credits itself.

The visual identity follows the two people: you're orange, your twin is blue. Cream paper cards make the stakes feel tangible, while the paired score makes it easy to see how you're both doing. I wanted the important things—the target, the card, and whose turn it is—to be easy to find.

Challenges I ran into

The tricky part was keeping two people on the same understanding of a deal. Which target applies? Does that photo count yet? Can this card still change? The backend needs one answer even when the phones reconnect at different times.

Monetization needed the same care. The core challenge is free. You can buy credits in Settings at any time. Re-rolls redraw next week's punishment card from the agreed deck and are available only before that week starts. Buying credits doesn't redraw a card, change the current week's punishment, or clear an existing one. Paying shouldn't undo a promise you already made to a friend.

App Review exposed a practical mistake: the purchase button originally depended on an upcoming card being available. Once that card locked, reviewers couldn't find it. I added a permanent Re-roll credits route in Settings and verified the purchase and credit delivery on a physical device.

More recently, I simplified the invitation. Requiring both friends to build a deck made accepting feel like another task. Now one person picks and the other reviews and accepts. I also changed onboarding to introduce the app before asking someone to create a challenge.

What I'm proud of—and what I learned

The first public release was September 23, 2026. Shipping my first app meant making all the small parts work together: the invitation, shared terms, photo review, weekly result, and punishment proof.

The biggest lesson was that working code isn't the same as a clear experience. A feature can be technically correct and still be hard to find. Real-device testing and revisiting the first-run flow changed decisions that had seemed obvious while I was building them.

I'm glad the original idea survived those changes. Two friends can both succeed. A bad week doesn't erase earlier weeks. And the app gives a small promise a little more weight without putting it in front of strangers.

What's next

I want to learn from real friend pairs: where they hesitate during setup, which cards they enjoy, whether both people bring proof, and whether they return for another week.

I want the first impression to feel like something you'd send a friend: picking a funny punishment, imagining their reaction, and deciding what you're both willing to put on the line. That's the part I want to share before explaining every rule. The next step is learning whether that interest turns into challenges people actually enjoy, without making claims about habit change.

Built With

Share this project:

Updates

Submission history