Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

319 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Spliit

Spliit is a free and open source alternative to Splitwise. You can either use the official instance at Spliit.app, or deploy your own instance:

Deploy with Vercel

Features

  • Create a group and share it with friends
  • Create expenses with description
  • Display group balances
  • Create reimbursement expenses
  • Progressive Web App
  • Select all/no participant for expenses
  • Split expenses unevenly (#6)
  • Mark a group as favorite (#29)
  • Tell the application who you are when opening a group (#7)
  • Assign a category to expenses (#35)
  • Search for expenses in a group (#51)
  • Upload and attach images to expenses (#63)
  • Create expense by scanning a receipt (#23)

Possible incoming features

  • Ability to create recurring expenses (#5)
  • Import expenses from Splitwise (#22)

Stack

Contribute

The project is open to contributions. Feel free to open an issue or even a pull-request! Join the discussion in the Spliit Discord server.

Contribute financially

Spliit is free, open source, and has no ads. Hosting, database and API costs are paid for by donations. If you want to help keep it that way, you can:

Contributions of any size are appreciated, and so is simply telling people about the project.

Translation

The project's translations are managed using our Weblate project. You can easily add missing translations to the project or even add a new language! Here is the current state of translation:

Translation status

Run locally

  1. Clone the repository (or fork it if you intend to contribute)
  2. Start a PostgreSQL server. You can run ./scripts/start-local-db.sh if you don’t have a server already.
  3. Copy the file .env.example as .env
  4. Run npm install to install dependencies. This will also apply database migrations and update Prisma Client.
  5. Run npm run dev to start the development server

End-to-end tests

The Playwright suite in e2e/ drives a real browser against the app running in Docker, so it exercises the same image users deploy. It needs Docker and a free port 3000, and nothing else β€” the stack builds itself from your checkout and throws its database away afterwards.

npm run e2e

That builds the image, starts app + PostgreSQL from compose.e2e.yaml, waits for /api/health/readiness, runs the suite and tears everything down. It never touches your development stack or ./postgres-data.

While writing tests it is quicker to keep the stack up:

npm run e2e:up                  # build and start, then leave it running
npm run e2e:test -- --ui        # iterate (also --headed, --grep, --debug)
npm run e2e:report              # open the HTML report of the last run
npm run e2e:down                # stop and delete the test database

--ui opens Playwright's UI mode, where you can pick tests, watch them run and step through a trace. It does not start the stack itself, so run npm run e2e:up first.

If port 3000 is already taken β€” by npm run dev, for instance β€” set E2E_HOST_PORT on every command of the session, including the test run:

E2E_HOST_PORT=3100 npm run e2e             # one-shot
E2E_HOST_PORT=3100 npm run e2e:up          # or, for the iteration loop
E2E_HOST_PORT=3100 npm run e2e:test -- --ui
E2E_HOST_PORT=3100 npm run e2e:down

The same suite runs in GitHub Actions from the E2E workflow, which can be triggered manually and runs automatically on release tags.

Run in a container

  1. Run npm run build-image to build the docker image from the Dockerfile
  2. Copy the file container.env.example as container.env
  3. Run npm run start-container to start the postgres and the spliit2 containers
  4. You can access the app by browsing to http://localhost:3000

Run with Docker compose

This is a sample docker-compose.yml file that you can use to deploy this web app.

name: spliit

services:
  app:
    image: ghcr.io/spliit-app/spliit:latest
    user: "1000:1000" # change to your user id or remove if you want root
    ports:
      - "8080:3000/tcp"
    environment:
      POSTGRES_PRISMA_URL: postgresql://spliit:spliit@database:5432/spliit
      POSTGRES_URL_NON_POOLING: postgresql://spliit:spliit@database:5432/spliit
    volumes:
      - ./app/cache:/usr/app/.next/cache
    depends_on:
      - database
    networks:
      - spliit

  database:
    image: postgres:17.3
    user: "1000:1000" # same as above
    environment:
      POSTGRES_USER: spliit
      POSTGRES_PASSWORD: spliit
      POSTGRES_DB: spliit
    volumes:
      - ./database/data:/var/lib/postgresql/data
    networks:
      - spliit

networks:
  spliit:

The web app will then be available on your host at http://localhost:8080/.

You can use named volumes in place of bind mounts if you prefer not having data stored inside local directories.

Health check

The application has a health check endpoint that can be used to check if the application is running and if the database is accessible.

  • GET /api/health/readiness or GET /api/health - Check if the application is ready to serve requests, including database connectivity.
  • GET /api/health/liveness - Check if the application is running, but not necessarily ready to serve requests.

Opt-in features

Expense documents

Spliit offers users to upload images (to an AWS S3 bucket) and attach them to expenses. To enable this feature:

  • Follow the instructions in the S3 bucket and IAM user sections of next-s3-upload to create and set up an S3 bucket where images will be stored.
  • Update your environments variables with appropriate values:
NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS=true
S3_UPLOAD_KEY=AAAAAAAAAAAAAAAAAAAA
S3_UPLOAD_SECRET=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
S3_UPLOAD_BUCKET=name-of-s3-bucket
S3_UPLOAD_REGION=us-east-1

You can also use other S3 providers by providing a custom endpoint:

S3_UPLOAD_ENDPOINT=http://localhost:9000

Create expense from receipt

You can offer users to create expense by uploading a receipt. This feature relies on OpenAI GPT-4 with Vision and a public S3 storage endpoint.

To enable the feature:

  • You must enable expense documents feature as well (see section above). That might change in the future, but for now we need to store images to make receipt scanning work.
  • Subscribe to OpenAI API and get access to GPT 4 with Vision (you might need to buy credits in advance).
  • Update your environment variables with appropriate values:
NEXT_PUBLIC_ENABLE_RECEIPT_EXTRACT=true
OPENAI_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXX

Deduce category from title

You can offer users to automatically deduce the expense category from the title. Since this feature relies on a OpenAI subscription, follow the signup instructions above and configure the following environment variables:

NEXT_PUBLIC_ENABLE_CATEGORY_EXTRACT=true
OPENAI_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXX

Analytics

Spliit can report anonymous usage events to an analytics service. It is disabled by default: nothing is loaded and nothing is sent unless you select a provider.

Select one with ANALYTICS_PROVIDER. The variables are read on the server, so a single Docker image can be configured when the container starts.

console β€” see what would be reported

Logs every event to the browser console and sends nothing anywhere. Useful while developing, and the shortest example of what a provider looks like.

ANALYTICS_PROVIDER=console

plausible

Reports to Plausible, a privacy-friendly, cookie-free analytics service. No extra dependency is installed: the provider is a script tag and a function call.

ANALYTICS_PROVIDER=plausible
PLAUSIBLE_DOMAIN=your-domain.com

For a self-hosted Plausible instance, point at it with PLAUSIBLE_HOST:

PLAUSIBLE_HOST=https://plausible.your-domain.com

Ad blockers drop requests to known analytics hosts. To avoid that, serve the script and the event endpoint from your own origin by adding rewrites in next.config.mjs and pointing the provider at them:

PLAUSIBLE_SCRIPT_URL=/js/script.manual.js
PLAUSIBLE_API_URL=/proxy/api/event

What is reported

Pageviews for a handful of pages, and one event per significant action: creating and updating a group, creating, updating and deleting an expense, attaching a document, scanning a receipt, and exporting expenses.

Group and expense IDs are never sent. They are the capability to read someone's group, so /groups/<id>/expenses is reported as /groups/[groupId]/expenses. Anonymization happens in one place, anonymizePath in src/lib/analytics/, between the call sites and every provider, and the event types forbid properties that are not explicitly declared β€” so leaking an ID is a compile error rather than a review question.

Pages are tracked explicitly, with <TrackPage path="…" />. A new route reports nothing until someone adds it, which keeps that a deliberate decision.

This is unrelated to the group activity log (the Activity tab), which is stored in your own database and is a product feature rather than analytics.

Adding a provider

Providers live in src/lib/analytics/providers/. Copy console.tsx, then register the new one in three places: provider-ids.ts, registry.ts, and config.ts (to map its environment variables to options). The last two are type-checked against the first, so npm run check-types tells you exactly what is missing.

A provider supplies a transport β€” where events go β€” and optionally a Script component if it needs to load an SDK.

License

MIT, see LICENSE.

About

Free and Open Source Alternative to Splitwise. Share expenses with your friends and family.

Topics

Resources

Stars

2.9k stars

Watchers

14 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages