Ritik Singh
Case study · GimmieAI · Founding Engineer

Some of what I built on Gimmie.

These are some of the things I am proud of here. Not all of it, just the parts that matter. I am the only engineer on the consumer side, so I take features from idea to launch, then live with them in production.

A lot of the real work is the small stuff that never shows up in a demo. Forward compatibility, so a change I ship today does not break an older app version still out in the wild. Idempotency, so a webhook that fires twice does not count twice. Handling the case where two things happen at the exact same moment. I care about those, and this job gave me the room to do them right.

01 · The hard one

Gift search

Request
Plan
Fan out
Merge
Rank
Cache

The hardest feature is search. You give Gimmie a loose idea, like a gift for my mom who loves gardening, and it has to come back with real products you can actually buy.

A Claude planner reads the request and what we know about the person, then writes a search plan. We do not just throw your words at a store. We shape the search differently per store, because each store has its own way that people search on it.

Then we fan out to several stores at once and pull everything back into one shape.

We remove duplicates across stores, and we rank the results so no single store takes over the page. We cache so a second visit is fast, and there is a regenerate option that gives you fresh ideas without repeating what it already showed you.

02 · The fun problem

Auth inside an iframe

Click provider
Popup
Login
postMessage
Set session

Gimmie also ships a widget that merchants drop into their own Shopify store. That created a fun auth problem.

The widget runs inside the merchant site, in an iframe. Login with Google or Apple will not run in an iframe, the providers block it. So when you click a provider, we open a popup instead. The popup finishes login on our own domain, then hands the session back to the widget.

The catch is that the widget and the popup are on different domains. My first idea was BroadcastChannel, but it only talks same origin. So I used window.opener.postMessage, which works across origins. The popup posts the session back, the widget listens, and I check the message type so the widget only trusts our own messages. Auth and the widget data also live in two separate Supabase projects, so the popup finishes auth on one and the widget sets the session on the other.

03 · Getting paid

Billing for the SaaS

One config
Atomic count
Commission
Hard cap
Credits

The widget is a paid product, so I built the billing too. There are a few plans, and each includes a set number of chats per month. Past that, we charge a usage based commission, with a hard cap so a merchant is never surprised by the bill. All of it comes from one config, so the price, the limits, and the commission never drift apart.

Two shoppers can chat at the same moment, so I count each chat with one atomic database step. Two at once cannot double count, or lose a count.

There are also referral credits, where a merchant earns free months and the commission still keeps working underneath.

04 · How it grows

Referrals, invites, notifications

Referrer
Web bridge
Connect
Fan out
Bell + push

This is how Gimmie grows, so I kept it as its own thing. Every user becomes their own referrer. When you invite someone and they join, we connect the two of you right away and let you know.

The attribution changed over time, and that part I like. We started on Branch for mobile, because a link has to survive an app install and still know who sent it. Later we moved to Tapfiliate. Tapfiliate is built around the web, so to make it work for app installs I put a small web page in the middle. A shared link now lands on that page first. The page registers the click with Tapfiliate, then deep links you into the app. So a mobile invite still gets proper credit, even though the tracking lives on the web.

Notifications run on a fan out on write model. When something happens, I write one notification per person right then, instead of working it out later when they open the app. The in app bell updates live, and mobile gets a push. Follows go through a single database trigger, so it fires the same way whether you followed someone yourself or got auto followed from an invite. And a new notification type needs no database change. An older app that does not know that type still shows a plain card instead of breaking. That last part is the forward compatibility I mentioned up top.

That is some of it

There is more in the product itself.