SliceOfPie
"Every bill-splitting app wanted sign-ups and sent your receipts to a server. I just wanted to scan, split, and share what everyone owes — with your payment info right there. One link, works in the browser."
Split bills without the awkward math. Snap a receipt, assign items, add tip, and share who owes what — all offline, all on-device.
Live Demo
Why
Every bill-splitting app I found either required everyone to sign up, needed an internet connection, or wanted my data. SliceOfPie runs entirely in your browser — no accounts, no backend, no tracking. Install it as a PWA and it works at the restaurant even without signal.
By the numbers
- Lighthouse (mobile): 99 performance, 100 accessibility, 100 best practices, 100 SEO. 0 ms of blocking time and no layout shift.
- About 26 KB of JavaScript (gzipped) to start. The scanner (about 36 MB) only downloads after you ask for it, then works offline.
- No accessibility issues found by axe on any screen, in light or dark.
- 199 unit tests and 42 end-to-end tests, each end-to-end test run on a phone and a desktop screen, all on every push.
- No framework: about 5,200 lines of TypeScript in 50 small modules.
Features
- Even or by-item split — tap people's names under each item (or tick their column on a computer); items nobody is on are flagged before you move on
- The answer first — the bill screen opens with what's owed back to you (or your share, if someone else paid), then each person's amount and a pie of the shares
- OCR receipt scanning — snap a photo with the in-app camera (guide frame, light and hold-still hints), upload one, drop or paste one on a computer, or share one from your gallery (Android, desktop Chrome). PaddleOCR reads it on-device in a Web Worker and picks out the items (including names that wrap onto a second line and "2 x" quantities), discounts, subtotal, tax, tip, total, merchant and date. A live line shows whether the items match the receipt's total, and a photo that can't be read or doesn't add up offers a retake. In an even split, a scan fills in the total
- Offline scanner, on your terms — the scanner (~36 MB) downloads once, after you say yes; Settings shows whether it's ready offline and can download or remove it
- Tip & tax — preset tip buttons, custom %, pre-tax or post-tax, round-up toggle; a tip already printed on a scanned receipt is used as-is instead of adding another
- Bill history — saved to IndexedDB under a name you choose, track who's paid with one tap; Home lists the bills still unpaid. The app asks the browser to keep it, and Settings exports it to a file and imports it back, for a backup or a new phone
- Share or copy — on a computer the bill copies to the clipboard in one click; on a phone it opens the share sheet. Either way your payment details (Venmo, Zelle, Cash App, or your own) are included, and there's a PNG version too
- Picks up where you left off — a reload, or the phone dropping the app while you open Venmo, brings you back to the same screen with the bill intact
- Works like an app — installable, with home-screen shortcuts (scan, enter a total, who owes me), the system back gesture, and updates that apply themselves (held back with a "new version ready" notice while you're in the middle of a bill)
- Phone, tablet and desktop layouts — tabs and a sticky action bar on phones, a live summary beside the steps on tablets, a side rail and a column per person on computers
- Accessible — axe finds no WCAG 2.2 AA issues on any screen in either theme; screen-reader announcements, native dialogs, a color-blind-safe person palette, and layouts that hold at 200% text
- Dark/light theme and currencies — follows your system or set manually; USD, EUR, GBP, JPY and more
- Privacy-first — no server, no analytics, no cookies. Everything stays on your device
What was hard
Reading receipts on the phone. I didn't want receipts going to a server, so OCR had to run in the browser. Tesseract.js was the obvious choice, but on my test images it only got every price right 4 times out of 16. I built a small benchmark page (npm run bench) and tried PaddleOCR's models on ONNX Runtime instead: 16 out of 16. That brought its own problems:
- Size. It's about 36 MB, so the app asks before downloading it, caches it for offline use, and cleans up old versions after an update.
- Speed. It runs in a Web Worker, so the page doesn't freeze while it reads.
- Matching prices to items. It reads each piece of text on its own, so I wrote the code that puts items and prices back on the same line, correcting for a tilted photo first. At 3.5° of tilt, prices were landing next to the wrong items.
The parser is tested against the OCR output of real receipts, so a change that breaks one shows up straight away.
Money that adds up. Splitting $100 three ways gives $33.333…, and rounding each share on its own showed "$66.67 owed back to you" next to two rows of $33.33. Now the shares are worked out in whole cents. Everyone else's share is rounded to the nearest cent, and whoever paid takes the leftover, so it's $33.33, $33.33 and $33.34. A 200-case test checks that the shares always add up to the bill. Along the way I found that 178.365 is stored as 178.36499…, so the total and the shares could round in different directions. Everything now rounds through one function.
This is the beginning of the README. Read the rest at the original. Read the full README ↗