It was 2 AM on a Tuesday when I had my "aha!" moment. I was scrolling through Instagram, saving yet another "easy 10-minute pasta" recipe to my collection. That's when it hit me—I had saved 147 recipes across Instagram, Pinterest, YouTube, and random PDF cookbooks, but I'd only cooked 3 of them in 6 months. The problem wasn't lack of inspiration. It was execution. I interviewed 50+ students and young professionals and found the same pattern everywhere: recipe hoarding is universal, but cooking is not. Three pain points emerged consistently:
Decision Paralysis: "What can I make with what I have?" remains an unanswered question every single day Ingredient Mismatch: Saved recipes require ingredients they don't own, creating friction Disorganized Storage: Screenshots scattered across platforms, PDFs buried in downloads folders
The insight that inspired CRAVE: People don't need more recipes—they need help using the ones they already have. The gap between "save" and "serve" is where most home cooking dreams die. I wanted to build the app I desperately needed—one that turns saved inspiration into actual served meals.
What it does CRAVE is an AI-powered cooking assistant that bridges the gap between saved recipes and actual meals. Core Features:
- AI Recipe Extraction
Upload PDF cookbooks → CRAVE extracts structured recipes using Gemini AI Paste Instagram/YouTube URLs → Automatically parses captions into ingredients and instructions SHA256 caching: Re-uploading the same PDF loads instantly (<1 second, no API call)
- Smart Pantry Matching
Track what's in your kitchen (ingredients automatically sync across devices) Real-time recipe matching with percentage scores (90%+ = "Cook Now", 70-89% = "Missing 1-2 items") Intelligent fuzzy matching: "chicken breast" matches "chicken", "greek yogurt" substitutes "heavy cream" 85-90% accuracy at <100ms (30x faster than AI-based matching)
- Auto-Generated Grocery Lists
One-tap "Add Missing to Grocery" from any recipe Smart de-duplication and categorization Check off items as you shop, optionally move to pantry
- Hands-Free Cook Mode
Voice-guided step-by-step instructions with text-to-speech Auto-detected timers from recipe text ("cook for 5 minutes" → timer starts automatically) WakeLock keeps screen on during cooking
- Freemium Monetization
Free tier: 10 recipes, basic matching, manual entry Premium ($4.99/month): Unlimited recipes, AI extraction, advanced matching, cloud sync Real Google Play Billing via RevenueCat (production-ready, tested in Internal Testing)
The User Journey: User saves recipe from Instagram → Pastes URL into CRAVE → AI extracts recipe → CRAVE matches against pantry (87% match - missing only soy sauce) → Tap "Add to Grocery" → Buy soy sauce → Start hands-free cook mode → Voice guides through steps with auto-timers → Meal served! 🎉
How we built it Sprint 1: Offline-First Foundation (Days 1-4) I started with Flutter and Hive for local storage. The philosophy: users should own their data immediately, no login required. dart// The pattern that became CRAVE's backbone Future addRecipe(Recipe recipe) async { // Write locally first (instant UI update) await Hive.box('recipes').add(recipe);
// Sync to cloud asynchronously if (authenticated) FirestoreService.sync(recipe); } Why offline-first?
Instant responsiveness (users don't care about your backend) Works without internet (cooking happens in kitchens, not coffee shops) Cloud features become additive, not required
Sprint 2: AI Extraction (Days 5-8) Original plan: Upload PDF → Cloud Functions → Gemini → Firestore (server-side) Pivot: Client-side extraction with read_pdf_text plugin + direct Gemini API calls Why?
Saved 4 days of Cloud Functions setup Faster extraction (no server round-trip) Better privacy (PDF never leaves device) Trade-off accepted: API key in client (would proxy via backend in production)
The 6-hour bug: Gemini API returned 404s for everything. After debugging network configs, API key formats, and Flutter HTTP settings, I discovered the issue: I forgot to enable the Generative Language API in Google Cloud Console. Sometimes the simplest solutions hide behind complex symptoms. Performance optimization: SHA256 hashing for PDF caching dartfinal hash = sha256.convert(pdfBytes).toString(); if (_cache.containsKey(hash)) return _cache[hash]; // <1s Re-uploads became instant. Users loved it. Sprint 3: The Matching Algorithm Decision (Days 9-11) The temptation: Use Gemini AI for recipe matching. It would handle edge cases "intelligently." The reality:
Gemini: 3-5 seconds per query, $0.01-0.05 cost, 85% uptime Deterministic: <100ms, $0 cost, 99.9% uptime
I chose deterministic. Why? Because for real-time features, speed is intelligence. Users perceive <100ms as "instant magic." 5 seconds feels broken, even if the AI is "smarter." The Smart Matching System (5 strategies in priority order):
Exact match (100% confidence): "chicken" == "chicken" Fuzzy match (90%): "chicken breast" contains "chicken" Substitution (80%): Database of 50+ common swaps (e.g., yogurt → cream) Category (60%): "tofu" is protein like chicken Staples (100%): Always assume salt, pepper, oil, water available
Weighted scoring (the math that makes it work): Match%=∑i=1nwi⋅ci∑i=1nwi×100\text{Match\%} = \frac{\sum_{i=1}^{n} w_i \cdot c_i}{\sum_{i=1}^{n} w_i} \times 100Match%=∑i=1nwi∑i=1nwi⋅ci×100 Where ( w_i ) is the ingredient weight and ( c_i ) is the match confidence. Weights:
Main ingredients (first 3): 40 points each Secondary: 15 points each Garnish (last 2): 5 points each
Result: Missing parsley barely affects score, missing chicken tanks it—exactly how humans think. Sprint 4: RevenueCat Integration (Days 12-14) Challenge: RevenueCat docs said "3 hours to integrate." It took me 9 hours. Why?
Understanding the flow: Play Console → RevenueCat → Entitlements → SDK The AAB requirement: You cannot test Google Play Billing via flutter run—you MUST upload to Internal Testing Service Account JSON permissions were wrong (regenerated with "View financial data" + "Manage orders")
The moment it worked: Seeing the real Google Play billing sheet appear on my phone. Not a mock, not a simulator—the actual production purchase flow. That's when CRAVE became a "real" app. Feature gating philosophy: Logic layer, not UI dartbool canAddRecipe() { if (isPremium) return true; return recipes.length < 10; // Free limit } UI gates are bypassable. Logic gates are not. Tech Stack
Frontend: Flutter 3.24, Provider, Material 3, Hive Backend: Firebase (Auth, Firestore, Storage) AI: Gemini 1.5 Flash for extraction Monetization: RevenueCat + Google Play Billing Images: Unsplash API for food photography
Challenges we ran into Challenge 1: The Black Screen of Death Symptom: After Firebase login, users saw a 2-second black screen before home screen appeared. Root cause: Navigation waited for Firestore sync to complete before rendering. Fix: Render immediately with cached data, sync in background. dart// Before: await FirestoreService.loadRecipes(); (blocking) // After: FirestoreService.loadRecipes(); // async, non-blocking Impact: Perceived load time: 2000ms → 200ms. Felt instant. Challenge 2: Comparison Anxiety The crisis: At 95% feature-complete (Day 9), I discovered competitor apps with "prettier" UIs. My reaction: Panic. "Should I redesign everything?" The spiral: Redesigning is fun (creative), testing is boring (repetitive). I almost fell into productive procrastination. Solution: Time-boxed UI polish (6 hours max). Focused on functional improvements, not visual overhaul. Lesson: Working features beat pretty mockups. Ship first, polish later. Comparison is the thief of shipping. Challenge 3: Scope Creep Temptation Features I killed to ship on time:
❌ Receipt scanning (cool but not core) ❌ Full YouTube transcript analysis (too slow, unreliable) ❌ TikTok recipe extraction (API instability) ❌ Social sharing features (nice-to-have) ❌ Meal planning calendar (complex, low immediate value)
Principle: Every "yes" to a new feature is a "no" to shipping on time. Result: Shipped 8 complete features instead of 13 half-working ones. Challenge 4: API Key Security Problem: Gemini API called from client → API key visible in decompiled APK Options:
Proxy through backend (4+ hours setup, kills speed advantage) Use flutter_dotenv + .gitignore (30 minutes, acceptable risk for MVP)
Choice: Option 2 with clear documentation for production hardening. Disclosure strategy: Be honest with judges that this is an MVP trade-off, show awareness of production requirements. Challenge 5: The Service Account JSON Maze Problem: RevenueCat couldn't fetch subscription data from Play Console. Debugging journey:
Checked API keys ✅ Verified product IDs ✅ Regenerated Service Account JSON ✅ Still broken ❌
Solution: The JSON permissions were wrong. Needed:
"View financial data" (for subscription info) "Manage orders" (for purchase validation)
Regenerated with correct permissions → worked instantly. Lesson: Cloud service integrations fail in subtle ways. Read the permissions docs carefully.
Accomplishments that we're proud of
- Shipping a Production-Ready App This isn't a prototype. CRAVE has:
✅ Real monetization (RevenueCat + Google Play Billing) ✅ Real user authentication (Firebase Auth) ✅ Real cloud sync (Firestore with offline persistence) ✅ Real AI integration (Gemini 1.5 Flash) ✅ Tested in Internal Testing with actual purchases
- The Smart Matching Algorithm I'm genuinely proud of choosing pragmatism over hype. Instead of using AI (the "obvious" choice), I built a deterministic system that's:
30x faster (<100ms vs 3-5 seconds) 100% reliable (no API failures) Works offline (no network dependency) 85-90% accurate (good enough for the use case)
The weighted scoring system with substitution awareness feels like magic to users, but it's just good engineering.
- Solving My Own Problem I built CRAVE because I needed it. The fact that 50+ people I interviewed had the exact same pain points validates that this isn't just "my" problem—it's a real market need. Validation moment: Testing with my roommate, she said "Wait, this actually works? I can finally use all those recipes I saved!" That made every late night worth it.
- Learning to Cut Features The hardest part of building CRAVE wasn't writing code—it was saying "no" to cool features that didn't solve the core problem. Killing receipt scanning hurt. Removing social sharing stung. But shipping 8 complete features beats building 13 broken ones.
- The Performance Numbers
PDF extraction: 10-page cookbook in ~8 seconds (first time), <1 second (cached) Recipe matching: 100 recipes matched in 89ms App launch: <2 seconds cold start Offline: 100% functional (all core features work without internet)
These aren't accidental—they're the result of deliberate architectural decisions.
- Revenue Model That Works Freemium is hard to get right. Too restrictive = users abandon. Too generous = nobody upgrades. CRAVE's free tier (10 recipes) is generous enough to evaluate the app, restrictive enough to incentivize upgrades. Early testing shows ~15% conversion intent, well above the 5% industry standard.
What we learned Technical Lessons
- Offline-first is harder but essential
Sync conflicts, migration logic, dual storage—all painful but worth it Users don't care about your backend architecture; they care about instant responsiveness
- AI is a tool, not a solution
Use AI where latency is acceptable (recipe extraction: 8 seconds is fine) Avoid AI where speed matters (matching: 5 seconds is broken, 100ms is magic) The best solution isn't always the most "impressive" one
- Test in production conditions
Emulators lie (especially for billing, storage, network) Real devices on real networks reveal truth Internal Testing isn't optional—it's where you discover what actually works
- Client-side extraction was the right call
Saved 4 days of Cloud Functions setup Faster performance (no server round-trip) Better privacy (PDF stays on device) The "API key exposure" trade-off was worth it for MVP speed
- Performance is a feature
<100ms matching feels instant → users call it "magic" 5-second AI matching feels broken → users blame the app Speed shapes perception more than accuracy does
Product Lessons
- Features are easy, simplicity is hard
I prototyped 13 features, shipped 8 The hardest decisions were what NOT to build Every feature adds cognitive load—ruthless prioritization is essential
- Freemium psychology is subtle
10 free recipes feels generous and fair 5 free recipes feels stingy and punishing The magic number depends on your use case, but it matters enormously
- Users want speed + reliability > AI branding
"AI-powered matching" that takes 5 seconds = users complain "Smart matching" that takes 100ms = users think it's magic Nobody asks "is this AI?" if it just works
- Real user research changes everything
I interviewed 50+ people before building Discovered: The problem isn't finding recipes, it's using them This insight shaped CRAVE's entire value proposition
Personal Lessons
- Shipping beats perfecting
I wanted to redesign the UI 3 times I wanted to add 5 more features I shipped instead, and that's why CRAVE exists
- Comparison is dangerous
Seeing "prettier" competitor apps almost derailed me Reminded myself: They might have pretty UI but broken features Your finished product beats their polished mockup
- Document your debugging
The 6-hour Gemini bug taught me to write down every failed attempt Those notes saved me 4 hours on RevenueCat issues Future me is grateful to past me
- Time-boxing prevents perfectionism
"6 hours max for UI polish" forced smart choices Constraints breed creativity and decisiveness Unlimited time leads to infinite tinkering
- The Flutter community is gold
Stack Overflow helped with Hive migration issues (20-minute fix) Reddit r/FlutterDev helped with Provider patterns Open-source maintainers responded to GitHub issues You're not alone—ask for help
Business Lessons
- Monetization validates seriousness
Free apps are weekend projects Paid apps are real products Implementing RevenueCat forced me to think like a founder, not just a developer
- Internal Testing is production
Upload AAB → Real billing → Real users → Real feedback This is where theory meets reality If it works in Internal Testing, it'll work at scale
What's next for CRAVE Immediate (Post-Shipyard - Week 1)
- Public Launch on Play Store
Move from Internal Testing → Production Prepare store listing (screenshots, description, video) Set up app analytics (Firebase Analytics, RevenueCat dashboard)
- First 100 Users Campaign
Friends, family, college campus (direct outreach) Reddit r/cooking, r/mealprep (community engagement) Product Hunt launch (tech early adopters)
- Critical Bug Triage
Monitor Firebase Crashlytics Set up in-app feedback mechanism Fix show-stoppers within 24 hours
3-Month Roadmap
- Receipt Scanning (Deferred from MVP)
Scan grocery receipts → Auto-add to pantry Use ML Kit for text recognition Reduces manual pantry management friction
- Nutrition Tracking
Calculate macros per recipe (protein, carbs, fat, calories) Leverage existing ingredient data + USDA database Premium feature (incentivizes upgrades)
- iOS Release
Flutter makes this mostly straightforward (1-2 weeks) App Store Connect setup RevenueCat already cross-platform ready
- Advanced Matching Enhancements
Quantity awareness: "You have 100g chicken, recipe needs 500g" → 50% quantity match Learning from behavior: Track which substitutions users actually use Seasonal ingredient prioritization: Boost recipes with in-season produce
6-Month Vision
- Community Features
User-contributed recipes (with moderation) "Made this!" photo uploads Recipe ratings and reviews Social proof drives engagement
- Smart Shopping Suggestions
"Buy paprika to unlock 10 more recipes" Strategic purchase recommendations Partner with grocery delivery APIs (Instacart, Amazon Fresh)
- Voice-First Cooking
Alexa/Google Home skill "Alexa, ask CRAVE what I can cook tonight" Hands-free interaction from pantry to plate
- Meal Planning Intelligence
"Plan my week" feature Balance variety, nutrition, cost Generate consolidated grocery list for the week
12-Month Goals User Metrics:
100,000 total downloads 5,000 paying subscribers ($24K MRR) 40% 30-day retention rate
Product Evolution:
Android + iOS parity 10+ supported languages (starting with Spanish, Hindi) Integration with 3+ grocery delivery services
Business Model:
Freemium + grocery affiliate revenue B2B: Partner with meal kit services Licensing: API for other food apps
The Long-Term Vision CRAVE becomes the universal cooking companion:
You save recipes → CRAVE organizes them You buy groceries → CRAVE tracks them You want to cook → CRAVE guides you You finish eating → CRAVE learned your preferences
The goal: Make home cooking as frictionless as ordering takeout. Why I'm Committed CRAVE started as a hackathon project, but it's solving a real problem I experience every day. Even after Shipyard ends, I'm committed to:
Iterating based on real user feedback Maintaining the app (bug fixes, updates) Growing it into a sustainable product
This isn't just a demo—it's the beginning of something real.
Built with late nights, Stack Overflow, and way too much coffee. Powered by determination and a refusal to let 147 saved recipes go to waste. ☕🚀
Log in or sign up for Devpost to join the conversation.