Inspiration

I spend way too much time saving cooking videos on Instagram and TikTok that I never actually cook. The recipes just sit there, buried in my saved folder. I wanted something that could take any cooking video or recipe link and turn it into something I'd actually use — a real recipe with ingredients, steps, and a grocery list I can take to the store.

When I saw the Shipyard brief, it clicked. This was the push I needed to actually build it.

What it does

Garnish extracts structured recipes from any URL — cooking videos, blog posts, whatever. Paste a link, and the AI pulls out the title, ingredients, steps, prep time, nutrition info, and even suggests tags. From there you can:

  • Save recipes to your collection and organize them into cookbooks
  • Generate grocery lists from one or multiple recipes
  • Track what's already in your pantry so you don't buy duplicates
  • Filter by favorites or recently added

There's a free tier (3 extractions/week, 10 saved recipes) and a Pro subscription that unlocks everything.

How I built it

The app is fully native iOS, built with SwiftUI and SwiftData for persistence. No UIKit anywhere.

The extraction pipeline works like this: the app sends a URL to a backend hosted on Railway, which scrapes the page content and feeds it to an AI model to extract structured recipe data (title, ingredients with quantities, steps, nutrition, tags). The response comes back as JSON and gets parsed directly into SwiftData models.

For images, I integrated the Unsplash API as a fallback — if a recipe doesn't come with a photo, the app searches for a relevant one automatically.

Subscriptions are handled through RevenueCat with three plans (weekly, monthly, annual). The paywall shows a feature comparison table and handles the full purchase + restore flow.

I tried to make the UI feel tactile — there's haptic feedback on primary actions, spring animations on buttons, shimmer loading states instead of spinners, and a confetti celebration when you subscribe. Small things, but they make the app feel alive.

Challenges I ran into

StoreKit testing was a headache. My subscription products were in "Ready to Submit" status in App Store Connect, which means they technically exist but StoreKit can't fetch them on a real device. I kept getting empty offerings from RevenueCat and couldn't figure out why. Eventually I set up a local StoreKit Configuration file so I could test the full purchase flow without waiting for Apple's approval.

Recipe extraction quality varies a lot. Some cooking blogs have clean structured data, others are walls of text with ads mixed in. Getting the AI to reliably extract the right info from messy pages took a lot of prompt iteration.

Getting the grid filtering right was trickier than expected. I had filter chips (All / Favorites / Recent) above a recipe grid, and tapping a filter would sometimes trigger navigation to a recipe instead of filtering. Turned out the filter buttons were inside the same ScrollView as the NavigationLinks, and the grid animation was causing cards to land under the tap point. Moved the filters outside the scroll view and it worked.

What I learned

  • RevenueCat's SDK is solid but the configuration dance between App Store Connect, RevenueCat dashboard, and StoreKit is where most people probably get stuck. The product IDs have to match exactly everywhere.
  • SwiftData is great for a project like this but has some quirks with relationships and preview data.
  • Shipping an MVP means being okay with "good enough." I cut a few features (meal planning, social sharing) to focus on the core loop: paste link → get recipe → cook.

Built with

Swift · SwiftUI · SwiftData · RevenueCat · Railway · Unsplash API

Built With

  • claude
  • railway
  • swiftdata
  • swiftui
Share this project:

Updates