Skip to main content

Automation

Utility Tracker

A private tool that watches my inbox for utility bills, reads each provider's format, and charts household cost and usage on one dashboard.

Year
2025–present
Role
Solo Developer
Status
Private tool
Utility Tracker dashboard
The tool itself is single-tenant and runs behind sign-in.

At a glance

  • 7Providers
  • 4Formats
  • MonthlyCollection

Overview

Tracking seven utility bills by hand meant seven websites and a spreadsheet every month. Utility Tracker connects to Gmail, recognizes each bill by sender, parses PDFs and JSON or CSV exports, and stores everything in one PostgreSQL schema. A dashboard shows monthly totals, year-to-date trends, the solar net-metering balance, and tiered water use, and a monthly job keeps it current without manual steps.

Result

  • No monthly data entry

    Bills arrive, get parsed, and land on the dashboard without anyone copying numbers into a spreadsheet.

  • One household view

    Net-metering balance, tiered water use, and year-to-date spending appear on one dashboard.

  • Format-agnostic parsing

    The same dataset whether a bill arrives as a PDF attachment, a JSON export, or a notification email.

  • Private by default

    Self-hosted and single-tenant. No third party gets a copy of household financial data.

Provider coverage

Each provider sends bills differently; the tracker brings them into one schema:

  • ElectricBill emails and PDF invoices, including the solar net-metering balance and time-of-use data
  • GasPayment confirmation emails plus JSON exports for usage and amount
  • WaterPayment confirmations and CSV imports with tiered usage
  • InternetNew-charge notification emails
  • TrashQuarterly PDF invoice attachments
  • Solar productionMonthly kWh exports from the installer's portal
  • HOA duesA fixed monthly amount

Pipeline and dashboard

A small Next.js app handles ingestion, normalization, and charts:

  • One-time Gmail authorizationThe refresh token is stored in PostgreSQL for ongoing access
  • PDF extractionpdf-parse pulls line items from invoice attachments
  • Provider-specific parsingEach provider has its own sender match and parser, with errors recorded for follow-up
  • Monthly jobCollects the last 30 days of bills automatically; a backfill endpoint can load 12 months on demand
  • DashboardMonthly totals, year-to-date trends, the net-metering balance, and tiered water use in Recharts

Technical architecture

A deliberately small stack, because the parsers are the point:

Frontend
Next.js 16 App Router with Tailwind
Database
PostgreSQL with Prisma 7 (four models: provider, bill, payment, OAuth token)
Email ingestion
Gmail API via googleapis with refresh-token rotation
PDF parsing
pdf-parse for invoice extraction
Charts
Recharts for monthly, year-to-date, and tier views
Hosting
Self-hosted on Hetzner via Coolify with a monthly job

Lessons

  • Gmail OAuth done rightConsent flow, refresh-token storage in the database, and silent rotation. The refresh token is the long-lived credential, so it lives in Postgres rather than an environment variable.
  • Parsing is the productEvery provider has quirks: one encodes the net-metering balance as a separate line, another rolls water use up by tier, a third uses its own timestamp format. The value is in the parsers, not the framework.
  • Lean by designNo multi-tenancy, auth library, or UI kit. The app serves one household, and every dependency I did not add is one I will not maintain.
  • Cron-driven data productsA scheduled call to a secret-protected endpoint is a simple pattern for periodic pipelines: no queues, workers, or orchestrator.

Let's talk.

Still moving data between inboxes and spreadsheets? I build focused automations that collect, normalize, and surface the information a team needs without adding another manual process.