The modern, real-time cost-splitting app built for simplicity.
Setil is a mobile-first progressive web app designed to simplify group expenses. Create a group, invite friends, and add expenses in seconds. Powered by Vue 3 and Firebase, Setil tracks every transaction in real-time, automatically calculating the most efficient way for everyone to setil up.
- 💸 Smart Settlement: Uses a greedy algorithm to simplify complex debts into the fewest possible payments.
- 🔥 Real-time: Powered by Firestore; balances and transactions update instantly across all devices.
- 🍰 Flexible Splitting: Split a single transaction between multiple people equally, or define specific amounts.
- 📱 PWA Support: Installable on iOS, Android, and Desktop for a native experience.
- 🔔 Notifications: Real-time alerts for new members, transactions, and payments.
- 🎨 Modern UI: Built using shadcn/vue, and Tailwind CSS for a clean and accessible mobile-first interface.
- 🔒 Secure Auth: Seamless and secure login via Google Authentication.
- ☁️ Serverless: Hosted on Vercel utilising Edge functions for high-performance API.
- Frontend: Vue.js 3, Vite
- UI Components: shadcn/vue, Tailwind CSS
- Database: Firebase Firestore
- Authentication: FIrebase Auth (Google)
- Deployment: Vercel (Frontend & Edge Functions)
Setil uses a greedy algorithm to resolve debts in
The resolveGroupDebts function (SettleUpPage.vue) categorises users into Creditors and Debtors, then matches them (using a highest absolute value heuristic) to minimise the total number of transfers.
Example
- Dave pays £100 for the Airbnb, split amongst all 5.
- Bob pays £50 for fuel, split between himself and Charlie.
- Dave pays £15 for snacks, split between Alice and himself.
- Charlie pays £20 for parking, split amongst all 5.
graph LR
%% The People
Alice((Alice))
Bob((Bob))
Charlie((Charlie))
Dave((Dave))
Eve((Eve))
%% Airbnb Debts
Alice -- "£20" --> Dave
Bob -- "£20" --> Dave
Charlie -- "£20" --> Dave
Eve -- "£20" --> Dave
%% Fuel Debts
Charlie -- "£25" --> Bob
%% Snack Debts
Alice -- "£7.50" --> Dave
%% Parking Debts
Alice -- "£4" --> Charlie
Bob -- "£4" --> Charlie
Dave -- "£4" --> Charlie
Eve -- "£4" --> Charlie
Global Balance Calculations:
| Person | Airbnb | Fuel | Snacks | Parking | Total |
|---|---|---|---|---|---|
| Alice | -(100/5) | -(15/2) | -(20/5) | -£31.50 (debtor) | |
| Bob | -(100/5) | -(50/2)+50 | -(20/5) | +£1.00 (creditor) | |
| Charlie | -(100/5) | -(50/2) | -(20/5)+20 | -£29.00 (debtor) | |
| Dave | -(100/5)+100 | -(15/2)+15 | -(20/5) | +£83.50 (creditor) | |
| Eve | -(100/5) | -(20/5) | -£24.00 (debtor) |
Therefore, recommended payments by matching creditors with debtors:
- Alice sends £31.50 to Dave
- Charlie sends £29 to Dave
- Eve sends £23 to Dave
- Eve sends £1 to Bob
graph LR
%% The People
Alice((Alice))
Bob((Bob))
Charlie((Charlie))
Dave((Dave))
Eve((Eve))
%% Resolved Debts
Alice -- "£31.50" --> Dave
Charlie -- "£29" --> Dave
Eve -- "£23" --> Dave
Eve -- "£1" --> Bob
git clone https://github.com/jcbyte/setil.git
cd setil
npm install- Update the Firebase configuration for your project at firebase.ts
Populate environment variables in Vercel:
| Variable | Description | Format |
|---|---|---|
| VITE_MAINTENANCE | Toggles maintenance mode | true or false |
| ENCRYPTION_KEY | AES-256-GCM Encryption Key for bank details | 32-byte (256-bit) key, encoded in Base64 |
| FIREBASE_PROJECT_ID | Your unique Firebase project ID | |
| FIREBASE_PRIVATE_KEY | Your Firebase Service Account private key | Newlines are written directly as \n within the text |
| FIREBASE_CLIENT_EMAIL | Your Firebase Service Account email |
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"npm run devOr, to run Vercel Edge Functions locally:
npx vercel dev