Work · Products · 11
Cartwise
Photograph a receipt, get a nutrition summary. The data entry is the whole problem.
- Type
- Products
- When
- 2026 · shipped
- Role
- Sole designer and developer. Parsing strategy, data model, interface, deployment.
- Scale
- One photograph in, an itemised nutrition summary out.
In plain language
Cartwise turns a supermarket receipt into a nutrition summary. You photograph the receipt, it reads the lines, works out what each abbreviated item actually is, and tells you what came into the house on that shop. It does not ask you to log anything, because the receipt was already written for you, and the reason nutrition apps get abandoned is not motivation, it is that logging is a chore you have to remember at the exact moment you least want to.
The question
Can the data-entry step be removed entirely, by using a record the shop already produced, instead of asking a person to reproduce it by hand?
Rough sketch
Where things sit on the screen, and in what reading order. Drawn, not screenshotted, so it stays true when the styling moves on.
Upload
Parsed items
Summary
Why nutrition apps die
They ask you to log what you ate. People do it for about nine days. The failure is not motivation. It is that logging is a chore you must remember, performed at the exact moment you least want to.
The bet
The receipt already knows. It is generated automatically, it is itemised, and it exists whether or not you decide to create it. Make the receipt the input and logging stops being a habit you have to maintain.
What it does
Upload a receipt photo. Items are parsed, matched against nutrition data, and summarised into what actually entered the house over that shop, as opposed to what was eaten, which is a different and much harder question the app does not pretend to answer.
The genuinely hard part
Item matching, not the nutrition arithmetic. Receipt lines are truncated, abbreviated and
retailer-specific: MLK SEMI 2PT has to resolve to semi-skimmed milk, two pints. Every
retailer abbreviates differently, and the same product reads differently across two shops. That
mapping is where the accuracy is won or lost, and it is the part that would need real work to
scale past one country’s supermarkets.
Stack
Next.js 15 with Prisma over a relational store, deployed on Vercel.
How it is put together
Left to right, the path a request or a record takes through the system.
01
Capture
- Receipt photo upload
- Text extraction
- Line splitting
The input already exists. That is the whole bet.
02
Resolve
- Truncated and abbreviated line items
- Retailer-specific shorthand
- Match to a known product
The genuinely hard part.
03
Enrich
- Nutrition lookup per matched item
- Quantity and unit normalisation
04
Report
- Per-shop summary
- History across shops
- What entered the house, not what was eaten
What happens, step by step
In plain language, in the order it happens.
Photograph the receipt
The one action the user takes. Everything after this is the app's problem.
Read the lines
The receipt is split into individual line items with quantities and prices.
Resolve each line to a real product
This is the accuracy bottleneck. Receipt lines are truncated, abbreviated and retailer-specific: MLK SEMI 2PT has to become semi-skimmed milk, two pints, and every retailer abbreviates differently.
Attach nutrition
Once a line is resolved to a product, the nutrition data is a lookup. This step is easy, which is exactly why the previous one matters.
Summarise the shop
The output describes what entered the house over that shop, deliberately not what was eaten, which is a different and much harder question the app does not pretend to answer.
Decisions, and what they cost
Every choice worth recording has a road not taken. Both are here.
The receipt as the input
instead ofManual food logging
Receipts are generated automatically, itemised, and exist whether or not the user decides to create them. Making the receipt the input means logging stops being a habit that has to be maintained, which is the failure mode, not a feature gap.
Report what was purchased
instead ofEstimating what was consumed
Consumption requires assumptions about waste, portions, sharing and timing that the receipt cannot support. Claiming to measure it would be a fabrication dressed as a feature; saying what it does and does not know is worth more than a bigger number.
A relational store through Prisma
instead ofA document store
Receipts, line items, products and nutrition records are a normalised graph with real joins across it. This is the shape relational databases are for, and the typed client removes a class of query bugs at compile time.
One country's retailers first
instead ofA general parser
Abbreviation schemes are retailer-specific and there is no universal grammar to generalise over. Matching well for a known set beats matching badly everywhere, and it names honestly what scaling would actually cost.
What came out of it
- Live and usable: photograph a receipt, get an itemised nutrition summary back.
- The data-entry problem is genuinely gone: the user takes one action, not thirty.
- The honest limit is stated in the product itself: it reports what was purchased, not what was eaten.
Still open
- Item matching is the accuracy ceiling, and it is retailer-specific. Scaling past one country's supermarkets is a real body of work, not a config change.
- No feedback loop yet where a user correction improves the next match.
Built with
- Next.js 15
- TypeScript
- Prisma
- Vercel