Skip to content

Sift

A camera-first personal decision engine. Point your phone at any product, restaurant, or item and get an instant verdict, score, and ranked alternatives pulled from real reviews and local options.

React Native Expo TypeScript Supabase Gemini NativeWind Edge Functions
// the problem

Every review app makes the problem worse

Sift was built as an entry for Handshake's Build with AI challenge, an ECPI-run competition where participants are given Codex credits and submit whatever they build with them. The constraint pushed the project toward something real and shippable rather than a toy demo.

The classic decision problem in a grocery store or a restaurant district: you're looking at something and you want a fast, honest answer about whether it's good. You could open several review apps, cross-reference them, weigh the star ratings against the number of reviews, and try to filter out the noise. In practice, almost nobody does that. You either trust a friend's recommendation, go with your gut, or spend five minutes on your phone that you didn't want to spend.

The interesting opportunity here is that modern multimodal models can take a photo of a product label, a restaurant sign, or a menu item and reason about it with actual context: what the item is, what the reviews say about it, how it compares to nearby options, whether it matches your stated preferences. That reasoning, delivered in a few seconds from a camera snap, is genuinely useful in a way that a search result isn't.

The other part of the problem is that most recommendation apps don't know what you actually care about. Price-sensitive shoppers and quality-first buyers need different verdicts on the same item. Sift solves this with explicit preference weights rather than inferred ones: you say what matters, and the model scores accordingly.


// how it works

Scan, score, decide

The core flow is fast: you open the camera, point it at something, and tap. The image goes to a Supabase edge function that passes it to Gemini along with any relevant review data and your preference profile. The model identifies what it's looking at, retrieves relevant signals, and returns a score out of ten, a one-sentence verdict, and a ranked list of alternatives within a few seconds.

The score is calibrated to feel useful rather than precise. A 7 means it's worth getting but not exceptional. A 4 means skip it. The verdict is always a single sentence because the point is speed, not justification. If you want the reasoning, you can tap through to the detail view.

The alternatives panel is often more useful than the verdict itself. If the thing you scanned is mediocre, knowing there's a better option two blocks away is the actually actionable information. The alternatives are ranked by distance, score delta, and preference match.

Preferences are five numeric weights on a 1-10 scale: price sensitivity, quality threshold, ethics weighting, health considerations, and speed of service. Those values live in a Supabase user_preferences table and get injected into Gemini's system prompt on every scan. Adjust a slider and the next scan reflects it immediately. There's no model training, no cold-start period, no black box. The preference system is just context passed to the model.


// the technical details

Camera handling, edge functions, and a deliberate model choice

React Native with Expo was the right choice for a camera-first app. Expo's Camera module handles permissions, preview rendering, and capture consistently across iOS and Android without native code. The tradeoff is that some low-level camera controls aren't accessible, but for a scan-and-judge use case, the high-level API is sufficient.

Latency was the main engineering challenge. The round trip from camera snap to verdict involves image encoding, network transfer, LLM inference, and response rendering. On a good connection this is under three seconds. On a slow connection it can stretch to six or seven. The UI handles this with a skeleton state that shows partial results as they arrive, so the interaction doesn't feel frozen.

Supabase edge functions handle the inference calls. This keeps API keys server-side and makes it straightforward to rate-limit by user. The edge deployment also puts the inference call geographically close to most users, which helps latency on the network transfer side.

Model selection was a deliberate tradeoff. Gemini 2.5 Flash returns a verdict in about two seconds. A more capable model takes closer to six. For something you're using in a store aisle or on a street corner, two seconds feels instant and six seconds feels broken. The cost is that Flash occasionally hedges on edge cases where a stronger model would be definitive. For most scans, the speed is worth it.