Webapp to keep track on subscriptions fees and has some math done for you.
👉 Try it at moebiusmania.github.io/subs-tracker
🖥️ Prefer the terminal? There's also a terminal version with the same features.
"...but exactly how much I'm spending right now with all the subscriptions services that I'm using right now?"
I guess that everyone of us has asked him/herself this question at least once in the last few years.
We use subscription services for every kind of needs nowadays, and most of them are more than legitimate to ask the money they are charging, but for us it's easy to lost track of the overall expenses with these solutions.
So that's what this app is doing: just insert the data of the subscriptions that you are using and it will do some easy math to tell you how much you are spending on a yearly and monthly basis.
Everything you type and "save" in the application is stored locally on your device using the LocalStorage browser API, so no data is moved anywhere on the Internet.
This may change in the future if I will consider the idea of adding a backend to make the app work across multiple device, but eventually this will be an opt-in feature with the local device data being always the default method.
At the moment there is an import/export functionality available in the app to move the data on another instance of the app (on another device), in two ways:
- a
.jsonfile with your subscriptions data; - a QR code: scan it with the camera of the other device and open the link. The subscriptions travel compressed inside the link itself (after the
#, the part browsers never send to a server), and the app asks before importing them. You can also copy the link and paste it in the import dialog.
It isn't the most convenient way to "sync" the data, but it easy to implement and keeps the complete ownership of personal data to the users. To keep every list small enough for one QR code, the app holds up to 40 subscriptions.
The app is available in English and Italian: pick one with the EN/IT switch at the top of the page. The choice is saved on your device, and on the first visit the app follows your browser's language.
The app is a PWA: you can install it on your home screen (or desktop) from the banner at the bottom of the page, or from the browser menu. On iPhone and iPad tap Share and then Add to Home Screen.
After the first visit it works offline too, since both the app and your data are kept on the device. When you open it online you always get the latest version: the offline copy is updated in the background.
There's also a version that runs in the terminal, with the same features: the stats, the subscription cards (toggle them active/inactive, edit or delete them), adding a subscription, export/import, delete all, light and dark themes, English and Italian. It works with both the keyboard and the mouse (click, hover and scroll wheel).
The web app needs a browser, and a browser isn't always there or isn't always handy:
- No graphical environment: headless servers, a Raspberry Pi without a display, minimal Linux installs or containers where there's only a shell.
- Over SSH: you can check and update your subscriptions on a remote machine from any terminal, without port forwarding or exposing a web server.
- Terminal-first workflows: if you live in the terminal (tmux, tiling window managers, keyboard-driven setups), it's quicker to run a command than to open a browser tab.
- Your data as a plain file: the data is a JSON file you can back up, sync with your own tools (git, rsync, Syncthing…) or move between machines, instead of being tied to one browser's storage.
- A single binary:
deno task tui:buildproduces a standalone executable with no runtime to install, easy to copy onto another machine.
It's not a separate app: it reuses the same logic as the web version, so the numbers always match, and the export/import files work in both. You can move your data from one to the other at any time.
$ deno task tui # run it
$ deno task tui:build # compile a standalone binary to dist/subs-tracker| Key | What it does |
|---|---|
Tab / Shift+Tab, arrows |
move between buttons, cards and fields |
Enter / Space |
press a button, toggle a card, submit the form |
↑ ↓ / mouse wheel |
change the price or the date in the form (PgUp/PgDn month) |
a e i |
add a subscription, export, import |
t / l |
switch theme / language |
Esc |
back, or close a dialog |
PgUp PgDn Home End |
scroll |
q / Ctrl+C |
quit |
The data is saved in ~/.config/subs-tracker/data.json (%APPDATA%\subs-tracker\data.json on Windows, or wherever SUBS_TRACKER_DATA points). It's the same format as the web app, and the export/import files work in both. The language follows your system locale until you pick one.
- Manage currencies (both per-entry and globally)
- Push Notifications?
- "Help/How it works" screen
- (still undecided) Signup/signin + Backend to sync data on multiple devices. As I said above if this will happen it will not be mandatory.
I'm not sure that this kind of simple app requires all of the effort of having a signup/signin system + a database just for the convenience of having the same data on multiple device. But if I'm going to do that in the future for whatever reason I'm going to use some pre-packaged solution that offers both a DB and social login authentication.
That's why the options that I'm considering for this part are pretty much similar:
- Firebase (Google), it works well but maybe I should stop relying too much on Google's stuff
- Supabase, claims to be "Firebase OSS alternative" seems nice but it's another SaaS
- Appwrite, is another "Firebase OSS alternative" but it offers an on-premise solution that can be hosted wherever you want, and in that case I would a basic Droplet plan on Digital Ocean.
Feel free to open an issue on this repo if you feel that you want to suggest some improvements or new feature.
You only need Deno 2.x installed: there is no Node.js, no package.json and no install step, dependencies are fetched and cached by Deno on first run.
Clone the repo
$ git clone https://github.com/moebiusmania/subs-tracker
$ cd subs-trackerstart the development server
$ deno task serveopen a browser at http://localhost:3000 and you will see the application.
All the available tasks:
| Task | What it does |
|---|---|
deno task serve |
dev server with live reload on http://localhost:3000 |
deno task dev:host |
same, but reachable from other devices on your network (phones, tablets) |
deno task build |
builds the static site into _site/ |
deno task build:gh |
builds for GitHub Pages, under the /subs-tracker/ path |
deno task test |
runs the unit tests |
deno task check |
formatting check, lint and type-check |
deno task tui |
runs the terminal version |
deno task tui:build |
compiles the terminal version to a standalone binary in dist/ |
The app is a static website: every page is plain HTML generated at build time, with a small script adding the interactivity in the browser.
- Pages are Vento templates in
src/(index.vtofor the home,add.vtofor the form), shared markup lives insrc/_includes/. - Interactivity is handled by Alpine.js:
src/js/main.tsis the only script, bundled by Lume with esbuild. - Business logic (costs math, the store, local storage and the UI components logic) lives in
src/js/lib/as plain TypeScript with no framework, so it's fully unit tested. - Offline & install:
src/sw.jsis the service worker. It loads everything from the network first and falls back to the cached copy when offline. At build time_config.tsfills in the list of files to precache and a version hashed from the whole site, so every deploy installs a fresh worker.src/manifest.webmanifestand the icons insrc/icons/make the app installable. - Terminal version lives in
tui/and uses deno_tui to draw and read the keyboard and mouse. A small declarative layer on top of it (tui/scene.ts) redraws only what changed, and the screens reuse the web app's store and component logic fromsrc/js/lib/, so both versions behave the same. - Styles are a single hand-written stylesheet,
src/styles.css, using modern CSS (cascade layers,@scope, nesting,light-dark(),@starting-style, view transitions) with no framework or preprocessor. Light and dark themes both meet the WCAG 2.1 AA contrast requirements, and animations are disabled when the system asks for reduced motion.
Unit tests use the built-in Deno test runner and live next to the code they test (*_test.ts in src/js/lib/ and tui/).
Every push and pull request runs the format, lint, type-check and test steps on GitHub Actions and builds the site. Pushes to main that pass them are then deployed to GitHub Pages.
- Deno - runtime and toolchain (tasks, tests, lint, format, type-check)
- Lume - static site generator, builds the pages as plain HTML
- Vento - templating language used by Lume
- Alpine.js - client side interactivity and state
- deno_tui - terminal rendering and keyboard/mouse input for the terminal version
- Inter - font, served by the privacy friendly Bunny Fonts
- Fraunces - serif for headings and figures, also from Bunny Fonts
- Lucide - icons
- uqr - QR code encoder for the share links
- Canvas UI Peel by David Haz - WebGL peel effect behind the add/edit dialog animation (MIT + Commons Clause)
- GitHub Actions & GitHub Pages - CI and hosting
This is an "hobby project" so if you like it and do you want to support me a little bit you could buy me a coffee ☕, and you would make me very happy (coffee is life essence for a developer!) 🥳.
Released under the MIT License.