A modern web app to track, compare and optimize all your digital subscriptions in one place. Built with React 18, TypeScript, Vite, TailwindCSS and Recharts. Designed for production deployment on GitHub Pages — 100% client-side, no backend required.
Tagline: Track. Compare. Save.
- Elegant dashboard with monthly / yearly cost, top category, and a financial-health score (0–100).
- Smart subscription manager: add, edit, duplicate or remove subscriptions.
- Built-in catalog of 30+ popular services (Netflix, Spotify, ChatGPT Plus, NordVPN, Free, Freebox, …).
- Side-by-side comparator (catalog or your own subscriptions).
- Savings simulator with real-time monthly / yearly impact.
- Advanced analytics: category pie chart, monthly distribution, 12-month forecast, top expenses, duplicate detection, cheaper-alternative suggestions.
- Alerts: upcoming renewals, forgotten subscriptions, price increases, redundant services, trial-period ending, monthly-budget overrun.
- Instant search and multi-criteria filters.
- JSON import / export and full local persistence (LocalStorage).
- Light / Dark / System theme, responsive mobile + desktop UI.
- French + English ready (
fr/en). - SEO ready: meta tags, Open Graph, sitemap, robots.txt.
- Code-split, lazy-loaded routes for fast first paint and a Lighthouse-friendly bundle.
- Installable PWA — works offline thanks to a generated service worker (
vite-plugin-pwa). - Command palette (
Ctrl/Cmd + Kor/) to jump to any page or run common actions. - Keyboard shortcut
Nto add a new subscription. - Drag & drop a JSON file anywhere on the window to import subscriptions instantly.
- Toast notifications for every import / export / save / delete action.
- Pin key subscriptions to keep them at the top of the list.
- Tags and trial period tracking with dedicated alerts.
- Monthly budget with visual progress bar on the dashboard.
- Table + cards views, sorting and detail page for each subscription.
- Onboarding modal with a one-click demo dataset to discover the app.
- Runtime validation on import so a malformed file can never corrupt your data.
- React 18 + TypeScript + Vite
- TailwindCSS with a custom design system (cards, buttons, inputs, badges)
- Recharts for interactive charts
- lucide-react icon set
- react-router-dom (HashRouter for GitHub Pages compatibility)
- LocalStorage persistence layer
src/
├── assets/ # static assets (kept for future use)
├── components/
│ ├── ui/ # Button, Card, Input, Modal, Badge, Logo, EmptyState
│ ├── dashboard/ # StatCard, HealthScore, UpcomingRenewals
│ ├── subscriptions/ # SubscriptionCard, SubscriptionForm, ServiceCatalog
│ ├── charts/ # CategoryPieChart, MonthlyBarChart, ForecastLineChart, TopExpensesChart
│ └── search/ # FiltersBar
├── pages/ # Dashboard, Subscriptions, Compare, Simulator, Analytics, Alerts, Settings
├── layouts/ # AppLayout (sidebar, mobile drawer, theme toggle)
├── hooks/ # useLocalStorage
├── services/ # storage, analytics, alerts, importExport
├── data/ # categories, catalog (popular services)
├── types/ # all TypeScript types
├── context/ # AppContext (subs, settings, theme, i18n)
├── utils/ # currency, frequency, dates, format
├── i18n/ # fr.ts, en.ts
└── styles/ # globals.css (Tailwind + design tokens)
# 1. Install dependencies
npm install
# 2. Start dev server
npm run dev
# → http://localhost:5173
# 3. Build for production
npm run build
# 4. Preview the production build
npm run previewTwo options — both work out of the box.
- Push this repository to GitHub.
- In the repository settings, go to Settings → Pages.
- Under Build and deployment, select Source: GitHub Actions.
- Push to
main. The workflow at.github/workflows/deploy.ymlbuilds and publishesdist/automatically.
npm run deployThis builds the project and pushes dist/ to the gh-pages branch using the gh-pages package. Then in Settings → Pages, choose Deploy from branch → gh-pages → /(root).
- The Vite
baseis set to./so the build works whether your site is hosted athttps://user.github.io/or under a project subpath likehttps://user.github.io/Sub-Compare/. - The app uses HashRouter, which makes deep links (
#/subscriptions,#/compare, …) work on Pages without server-side rewrites. - A
404.htmlSPA fallback is included for additional robustness.
interface Subscription {
id: string;
name: string;
price: number;
currency: "EUR" | "USD" | "GBP" | "CHF" | "CAD";
frequency: "weekly" | "monthly" | "quarterly" | "biannual" | "yearly";
category:
| "streaming" | "music" | "cloud" | "ai" | "vpn"
| "gaming" | "telecom" | "internet" | "other";
startDate: string; // YYYY-MM-DD
renewalDate: string; // YYYY-MM-DD
logo?: string; // SVG markup or URL
description?: string;
priceHistory?: PricePoint[];
notes?: string;
active?: boolean;
}All conversions to monthly / yearly equivalents are handled by src/utils/frequency.ts. Cross-currency comparisons use static, offline ratios in src/utils/currency.ts to keep the app deployable without a network backend.
- Route-level code splitting via
React.lazy+Suspense. - Manual vendor chunks (
react,charts,icons) via RollupmanualChunks. - Lazy SVG logos rendered inline (no extra HTTP requests).
- Tailwind purges unused classes for a tiny final CSS.
- No runtime API calls — everything works offline once loaded.
MIT — feel free to fork, adapt and ship.