Theo Gieruc

I Built Branger Because Bring!'s Recipe UX Drove Me Crazy

My girlfriend and I use Bring! every week. The shared shopping list is genuinely great: real-time sync, clean UI, we both see what’s been checked off as we walk through the store. No complaints there.

But Bring!‘s recipe feature? Terrible. And I keep finding recipes everywhere:

  • A TikTok video with the recipe flashing on screen for 3 seconds: screenshot it
  • A food blog buried under 2000 words of life story: copy the URL
  • A cookbook at a friend’s place: snap a photo of the page
  • A conversation with Claude about what to cook tonight: …copy-paste into Notes?

Every time, the same friction: manually typing ingredients, losing the original source, forgetting where I found it. I wanted something that could take a recipe from any of these sources and turn it into a structured recipe with one tap, then send the ingredients straight to a shopping list.

So I built Branger (Bring + banger).

The Stack

  • Frontend: React Native + Expo SDK 54 with Expo Router
  • Backend: Supabase (PostgreSQL, Auth, Storage, Edge Functions)
  • AI: Mistral Large for recipe structuring, Mistral OCR for photo text extraction
  • MCP: A custom MCP server so Claude can manage my recipes directly
  • Hosting: Self-hosted on my Proxmox server, behind Caddy + Cloudflare Tunnel

No external backend server. Supabase handles auth, database, storage, and serverless functions. The entire “backend” is PostgreSQL + Edge Functions.

The AI Recipe Pipeline

This is the core of Branger. Three import methods, all converging into the same structured format: title, ingredients (name + amount), and steps.

URL Import: “I found this recipe blog”

The most common case. Paste a URL, get a recipe.

Once the page is fetched, the HTML is cleaned up (scripts and styles stripped, entities removed, text truncated to 15,000 characters). No headless browser needed; recipe blogs are mostly server-rendered.

The cleaned text then goes to Mistral Large with a system prompt that extracts title, ingredients, and steps as structured JSON. The prompt separates ingredient names from quantities (“butter” as the name, “2 tablespoons” as the description) because when you add ingredients to a shopping list, you want “butter” as the item, not “2 tablespoons of butter” as one blob.

Photo Import: “I saw this in a cookbook”

This is the two-stage pipeline. First OCR, then structuring.

Each photo (up to 10) is sent to Mistral’s OCR API, which extracts text from the image. The results are concatenated and then passed to Mistral Large with a specialized prompt that knows it’s dealing with OCR output. It corrects obvious misspellings and deduplicates content from overlapping photos. This handles the common case of taking two overlapping photos of a cookbook spread.

Text Import: “I have this recipe written down”

The simplest path. Paste any freeform text (a message from a friend, a note from your phone, whatever) and Mistral Large structures it. Same pipeline, different system prompt that’s more forgiving about input format.

The Frontend Flow

All three methods land in the same place: a review screen where you can edit the AI’s output before saving. Every recipe tracks its source type (manual, text, URL, or photo) and source URL when applicable, so you can always trace back to where a recipe came from.

The MCP Server: “Hey Claude, Add This Recipe”

I built a Model Context Protocol server so Claude can directly interact with my recipes and shopping lists.

The MCP server is a Supabase Edge Function that speaks JSON-RPC 2.0 over HTTP. It exposes 14 tools: recipe CRUD, recipe import from URL or text, and full shopping list management (create lists, add items, check items off, remove items).

So in Claude, I can say “find me a good carbonara recipe and add the ingredients to my weekend shopping list,” and it actually does it. It searches the web, imports the recipe, saves it, and adds the ingredients to my list. All in one conversation.

Dual Authentication

The MCP server supports two auth methods: API tokens (generate one in the app, works with any MCP client) and OAuth 2.1 (for Claude Desktop and other clients that support automatic authentication flows).

Real-Time Collaborative Shopping Lists

The shopping list feature uses Supabase Realtime for live sync between devices. When my girlfriend checks off “tomatoes” at the store, I see it update instantly on my phone.

The app subscribes to PostgreSQL change events for the active list; inserts, updates, and deletes all propagate in real time. All item mutations are optimistic: the UI updates immediately, and if the server rejects the change, it rolls back to the previous state. This makes the app feel snappy even on slow connections.

There’s also an offline queue. If you lose connection in the store (basement supermarkets, anyone?), changes queue up locally and replay when you’re back online. An offline banner lets you know what’s happening.

Self-Hosting on Proxmox

The web version runs on my Proxmox homelab: static files served by Caddy in an LXC container, publicly accessible via Cloudflare Tunnel. Edge functions and AI run on Supabase and Mistral’s infrastructure.

The Database

The schema is straightforward but has a few nice touches:

Shopping lists have no single owner. A list is just a list; a join table tracks who has access. When the last member leaves, a PostgreSQL trigger automatically deletes the list. No orphaned data.

Recipes track their origin. Every recipe stores whether it was created manually or imported via text, URL, or photo, plus the source URL when applicable. Useful when you want to revisit the original blog post or share the source with someone.

Shared recipes use opaque tokens. Instead of exposing database IDs in public URLs, each shared recipe gets a random token. Anyone with the link can view the recipe without needing an account.

What I Actually Use It For

Every week, roughly the same flow:

  1. During the week, I save recipes as I find them: URL from a blog, photo from a friend’s cookbook, or directly from a Claude conversation.
  2. On the weekend, I pick what to cook and tap “Add to list,” and the ingredients go straight to our shared shopping list.
  3. At the store, my girlfriend and I both have the list open, checking things off in real time.

The biggest source of recipes, honestly, is TikTok. I’m addicted. The problem is you can’t copy-paste from video descriptions, so my workflow used to be: pause the video, screenshot the recipe, open Notes, squint at the screenshot, manually type out the ingredients. Now I just screenshot it and drop it into Branger. The OCR pipeline handles the rest.

It’s not trying to be a social recipe platform or a meal planner. It’s just a recipe box that accepts input from everywhere and feeds into a collaborative shopping list. The thing Bring! should have been.


Branger is open source at github.com/tgieruc/Branger. Built with React Native, Expo, Supabase, and Mistral AI.