Project 01 · Consumer iOS · 2026

Nobody finished onboarding. Personalization worked anyway.

Sift is a taste-first event app for New York, co-built and shipped to the App Store. We designed an onboarding flow to learn your taste before you saw a single event. Not one user finished it. The recommender reached full confidence for most of them anyway.

My roleCo-founder, product and engineering
TeamFour co-founders
StackReact Native, Expo, Supabase
StatusLive on the App Store
0 of 41completed the taste-setter
60%reached full confidence (n≈25)
20.5%App Store conversion, 79 views
01 · Deck
01 · Deck
02 · Taste-setter
02 · Taste-setter
03 · Event
03 · Event
04 · Import
04 · Import
01

The problem

New York has more events on any given night than a person could evaluate in a week, and almost none of them are relevant to any particular person. We ran 20 user interviews before writing product code. Two findings shaped everything after.

The first was fragmentation: 87% of the 18–35 New Yorkers we spoke to used three or more apps to figure out what to do, usually some mix of Google Maps, Eventbrite, Instagram, Resy, and a group chat. The second finding was a negative result, and it mattered more. Zero interview subjects asked for another social feed. What they described wanting was an answer, not more to look through.

“We spend most of our time looking into activities we end up not even going to. We just get overwhelmed and give up.”

Sam, 23 · user interview

“Honestly? I don’t want another social media app. I just want to know what’s good this weekend.”

Recurring theme across 20 interviews

That pushed us away from a feed and toward a ranked deck, one card at a time, ordered by predicted fit, creating a cold-start problem. A recommender with no signal cannot rank, so we did the obvious thing and asked the user up front.

02

What I built

The client is React Native on Expo and the backend is Supabase. Most of the work went into the ingest pipeline and the scoring loop.

Six live scrapers pull from Dice, Resident Advisor, Luma, Fever, NYC museums, and Eventbrite, refreshed every three days via GitHub Actions. Claude Sonnet finds what the scrapers miss and pulls in a curated "high-taste" list of events, mostly involving pop-ups, sample sales and gallery openings. Then everything gets cut hard. An LLM rubric rejects tourist traps, corporate spam, and children's events, which removes roughly 85% of incoming inventory. What survives gets a vibe score from 1–10 via gpt-4o-mini; anything under a score of 5 never loads.

Aggregators need the firehose because their economics depend on total inventory. Ours didn't, so we could afford to throw most of it away. Rejection is the product.

~85% removedEVERYTHINGTHE DECKSOURCES6 scrapersDice, RA, Luma, Fever,NYC museums, EventbriteDISCOVERClaude Sonnetpop-ups, sample sales,gallery openingsREJECTLLM rubrictourist traps, spam,children's eventsSCOREgpt-4o-minivibe 1–10under 5 never loadsRANKper-user signalscategory, tag,borough, priceREFRESHED EVERY THREE DAYS VIA GITHUB ACTIONS
The band is drawn to scale. Everything upstream of the rubric is inventory an aggregator would ship; roughly 15% of it survives to the deck.

On the client, every swipe carries intent. Each gesture updates four independent signals (category, tag, borough, price band) and the deck re-ranks in under 200ms.

GestureIntentSignal effectWeight
RightGoingCategory, each tag, borough+0.15 / +0.08 / +0.06
LeftNot nowNo taste effect; resurfaces in 2–5 days0.00
DownNot interestedCategory penalty; 3 strikes hides permanently−0.05
UpInspectOpens detail, deliberately no signal—

Cold start blends quality and timing for roughly the first 20 swipes, then hands over to personalized ranking. That threshold is what confidence measures. I built it as an internal diagnostic, a way to check if he recommender had enough signal before we trusted it. It turned out to be the most important number in the product.

03

What the data said

We launched with no paid acquisition. The App Store funnel was healthy. 157 impressions, 79 product page views, 18 first-time downloads, a 20.5% conversion against Apple’s typical 5–7%. With 23 seeded TestFlight users still active, that put us at 41 people.

Acquisition · App Store, launch to week 3, zero spend
Impressions
157
Product page views
79
First-time downloads
18
20.5% page-view-to-install. Strong ratio, small denominator. 79 views is not a stable estimate, so I'd treat it as directional rather than a benchmark claim.

Then I pulled the onboarding funnel expecting a drop-off curve, and got something that didn’t resolve.

Personalization · all 41 users
Opened the app
41
Started the taste-setter
17
Finished the taste-setter
0
Reached full confidence
~25
Zero out of 41 finished it. Roughly 60% of active users reached full personalization confidence anyway, through swipes, saves and repeat category visits.

The mechanism was in our own design and we hadn’t noticed it. Cold start hands over to personalized ranking after about 20 swipes. Twenty swipes takes under two minutes. The taste-setter was asking users to spend ninety seconds declaring preferences the deck would infer from two minutes of ordinary use.

The onboarding flow wasn’t a bottleneck we needed to widen. It was a question the product was already answering by watching.

The finding

This surfaced because two independent sources agreed. A heuristic UX audit flagged the flow as skippable friction; separately, the scoring code showed confidence accumulating for users who had never touched it. Neither alone would have been convincing, since the audit could have just been my taste and the score could have been a bug. The finding lives in the agreement between them.

On the numbers

Every figure here comes from a launch cohort of 41 users. The percentages are honest but the denominators are small: 60% is roughly 25 people, and the zero is a genuine zero rather than a rounding artifact. I’d re-run all of it at 1,000 users before treating any of it as settled. The direction was clear enough to act on though, and a design decision that costs every new user ninety seconds doesn’t need p < 0.05 to be worth revisiting.

04

What I'd do next

Cutting the taste-setter is the obvious move and the least interesting one. What I'd actually want to know is what else in the product asks for information it could observe instead.

  • Cut the taste-setter entirely; keep one optional neighbourhood prompt at first save, where intent already exists
  • Surface confidence to the user as a reason (you’re seeing this because you saved three like it), turning an internal diagnostic into trust
  • Instrument the inverse: which users never reach confidence, and what they have in common
  • Re-run the audit against the scoring code each quarter, since that pairing is what caught this

Instrument the implicit path before you build the explicit one. That's the lesson I took into everything after. We built the questionnaire because it was the legible solution, and only found out it was redundant because we happened to have logged the alternative.