A free, open-source Splitwise alternative for trips β split expenses with friends on a Google Sheet you own. No server, no account, no signup, no app to install.
index.html is the whole app. AppsScript.gs is the whole backend, running inside your
sheet. Nothing else exists β no database, no hosting bill, no company holding your data.
- Equal, partial, and custom splits
- Who owes whom, in the fewest payments that clear the trip
- A personal view: what you lent and what you owe, per expense
- One ledger of every expense and payment, editable in place
- Several trips at once, switched from the top-left
- Built for a phone: bottom tab bar, one-tap settle, skeletons while it loads
Only the first person does this. Everyone else just opens an invite link.
- Create a blank Google Sheet. This is the trip.
- Extensions β Apps Script. Delete whatever is in the editor.
- Paste
AppsScript.gsand save. The app's setup screen has a Copy button for it, so you never need this repo. - Run
setupSheetsonce. Pick it from the function dropdown, press Run, and grant the permissions β it is your own script asking for your own sheet. It creates every tab. - Deploy β New deployment β Web app, with:
- Execute as: Me
- Who has access: Anyone
- Copy the
/execURL and paste it into the app.
Open the app and it will walk you through exactly these steps.
Trip menu (top-left) β Copy invite link. It produces:
https://kothariji.github.io/trip-split/?trip=<the /exec URL>
Anyone who opens it is connected instantly and skips all six steps. The link only accepts
script.google.com URLs, so it can never point the app at another host.
β οΈ Anyone with the link can read and write the trip. It is the key to the sheet β share it the way you'd share the sheet itself, and don't post it anywhere public.
Splitwise is good. This exists because a trip's money is a spreadsheet problem, and a spreadsheet you own beats an account you rent:
| Trip Split | Splitwise | |
|---|---|---|
| Your data | A Google Sheet in your Drive | Their database |
| Account | None | Required, per person |
| Cost | Free, no limits, no ads | Free tier with paid upgrades |
| Editing outside the app | Open the sheet and type | Export and re-import |
| Custom reporting | It's a spreadsheet β pivot it | Export and hope |
The app is served by GitHub Pages from main, so a push to main deploys it.
AppsScript.gs is embedded inside index.html between the gs:embed markers, so the setup
screen can hand it out. They must stay identical. After editing the .gs:
python3 - <<'PY'
import io, re
gs = io.open('AppsScript.gs', encoding='utf-8').read()
s = io.open('index.html', encoding='utf-8').read()
s = re.sub(r'\n<!-- gs:embed:start -->.*?<!-- gs:embed:end -->\n', '\n', s, flags=re.S)
block = ('\n<!-- gs:embed:start -->\n<script type="text/plain" id="gsSource">\n'
+ gs + '</script>\n<!-- gs:embed:end -->\n')
marker = '\n<script>\n/* ============================================================\n CONFIG'
io.open('index.html', 'w', encoding='utf-8').write(s.replace(marker, block + marker))
PYExisting trips then need Manage deployments β New version in their own Apps Script
editor. The /exec URL stays the same, so no invite links break.
| What | How |
|---|---|
| Backend maths | Run runSelfTest in the Apps Script editor β logs self test OK |
| Frontend maths | Open the app with ?selftest β logs to the console |
| Syntax | node --check on either file |
Both self-tests cover the money paths: splits, balances, settle-up, dates, and the personal view. They touch no data.
| Tab | Columns |
|---|---|
| Trip | field | value β name, description, startDate, endDate |
| People | name | active |
| Tags | tag | emoji |
| Expenses | id | paidBy | description | amount | tag | splitBetween | splitMode | timestamp | date |
| Settlements | id | fromPerson | toPerson | amount | note | timestamp | date |
date is the day the money moved and drives every total; timestamp is when the row was
written and only breaks ties within a day.
People and categories are derived from the rows themselves β anyone who appears as a payer, in a split, or in a settlement is on the trip. The People and Tags tabs are just seeds for names you want to see before their first expense.
Columns are matched by the header row, not by position, so renaming case or reordering
columns is safe. setupSheets is re-runnable and never overwrites data.