Most personal finance apps want access to your bank accounts. I didn’t want that.
Instead, I built a system that processes bank statement PDFs, categorizes every transaction, and generates an interactive dashboard—all locally, with no data leaving my machine except monthly summaries.
Here’s how we built it.
The Problem
I have multiple bank accounts (current account, two credit cards). Each sends monthly PDF statements. To understand my spending, I needed to:
- Download PDFs from Google Drive
- Extract transactions from three different statement formats
- Categorize hundreds of transactions per month
- Track trends over time
- Identify spending patterns
Doing this manually? Impossible. Using a third-party app? Privacy nightmare.
The Solution: Build It With AI
I worked with OpenClaw (my AI assistant) to design and implement a complete pipeline. Not “I asked it to write code.” More like pair programming, iterating on design, fixing edge cases, and refining categorization rules through conversation.
Phase 1: Planning the System
Me: “I want to track spending across three bank accounts. Statements are PDFs in Google Drive. I need categorization, trends, and monthly reports.”
OpenClaw: Created a comprehensive design doc covering:
- Category structure (Essential/Lifestyle/Financial/Other)
- Technical architecture (data pipeline diagram)
- Automation schedule (when to process statements)
- File formats (transaction database, categorization rules)
We discussed statement cadence: one account closes on the 31st, another on the 27th, a third on the 6th. That meant all three statements for a given month would be available by ~6th of the following month.
Decision: Process on day 8 (all statements available), report on day 15 (after manual review).
Phase 2: Parsing PDFs
This was the hardest part. Each bank has a different PDF format:
Bank 1 (Current Account):
Date Description Paid out Paid in Balance
01 Oct SUPERMARKET 45.32 3,427.18
01 Oct SALARY DEPOSIT 3,000.00 6,427.18
Bank 2 (Credit Card):
01 Oct 2025 RESTAURANT -67.89
02 Oct 2025 REFUND +25.00
Bank 3 (Credit Card):
Oct 01 MERCHANT NAME 123.45
Multi-line description continues
here with more details
Each required a custom parser. We used pdftotext to convert PDFs to plain text, then regex patterns to extract:
- Date (various formats)
- Merchant name (cleaned, normalized)
- Amount (positive/negative)
- Running balance (when available)
The Multi-Line Challenge
Bank 3 was tricky: some transactions spanned multiple lines. If a description wrapped, the parser would treat it as a separate transaction.
First attempt: Naive line-by-line parsing → duplicate transactions.
Solution: Build a state machine that:
- Detects transaction start (date pattern)
- Accumulates continuation lines
- Merges into single transaction
- Validates amount + date consistency
We debugged this interactively in Telegram. I’d paste problematic transaction examples (with merchant names anonymized), OpenClaw would revise the parser, we’d test again.
Result: 100% transaction extraction accuracy across 1,700+ transactions.
Phase 3: Categorization Rules
With transactions extracted, we needed categories. I didn’t want 500 micro-categories. I wanted high-level insights.
Categories we defined:
- Essential: Housing, utilities, groceries, transport
- Lifestyle: Dining, entertainment, travel, subscriptions
- Financial: Savings, debt payments, bank fees
- Other: Gifts, professional services, miscellaneous
Building the Categorization Engine
We started with exact matching:
{
"SUPERMARKET CHAIN": "Groceries",
"GAS COMPANY": "Utilities",
"TRANSPORT AUTHORITY": "Transport"
}
Then added fuzzy matching for merchant name variations:
{
"pattern": "SUPERMARKET|GROCERY|FOOD STORE",
"category": "Groceries"
}
The Interactive Mapping Process
Here’s where it got interesting. I didn’t sit down and write 200 categorization rules upfront. We did it conversationally:
Me: “The transaction from ‘ONLINE RETAILER’ should be Shopping.”
OpenClaw: Updates rules, re-categorizes, shows new accuracy rate
Me: “All transactions with ‘TAXI’ or ‘CAB’ in the name should be Transport.”
OpenClaw: Adds fuzzy pattern, applies to all matching transactions
This happened right in the Telegram chat. No code editor. No terminal. Just conversation.
After 20-30 iterations, we had:
- 200+ merchant rules
- 95%+ auto-categorization accuracy
- Edge cases documented
Key lesson: Build categorization rules iteratively, not upfront. You don’t know your spending patterns until you see the data.
Phase 4: Monthly Reports
With transactions categorized, we needed actionable insights.
Monthly report structure:
- Income vs. spending summary
- Breakdown by category group
- Top categories and merchants
- Month-over-month comparison
- Categorization stats
Reports route to a dedicated Telegram topic (Finance #356) on the 15th of each month.
Why day 15? Gives me a week to review uncategorized transactions and correct any mis-categorizations before the final report.
Phase 5: Visualization
Text reports are fine for quick checks. But to understand trends, I needed charts.
Requirements:
- Interactive (click to filter)
- Local-only (no data uploaded)
- No build step (single HTML file)
We built a standalone dashboard.html using Chart.js:
Charts included:
- Spending by Category (doughnut chart, click legend to filter)
- Monthly Trend (bar chart with income/spending/budget comparison)
- Spending by Group (pie chart for Essential/Lifestyle/Other)
- Top 10 Merchants (horizontal bar chart)
- Savings & Investments tracker
Interaction model:
- Click on a category → filter entire dashboard to that category
- Click on a merchant → see all their transactions
- Sort transaction table by any column
- Search by merchant name
Data privacy: The dashboard runs entirely in the browser. It reads a local transactions.jsonl file via the file picker. No data is uploaded anywhere.
Publishing an Anonymized Version
To share the tool, I created a public GitHub repo with:
- The dashboard HTML (single file, 750 lines)
- Sample transaction data (generic/mocked)
- Example categorization config
- Documentation
Repo: https://github.com/czgroup/personal-spend-tracker
Everything personal (real transactions, category budgets, merchant names) is in .gitignore. The public version contains only the tool, not my data.
The Full Automation Pipeline
Here’s what runs automatically each month:
Day 8 @ 23:00 (Processing)
- Download new PDF statements from Google Drive
- Extract transactions using account-specific parsers
- Auto-categorize using 200+ merchant rules
- Send notification: “X transactions processed, Y need review”
Day 15 @ 09:00 (Reporting)
- Generate monthly summary for previous month
- Calculate trends and anomalies
- Send formatted report to Telegram Finance topic
All orchestrated via OpenClaw cron jobs.
What This Approach Enables
1. Privacy by Design
- Bank PDFs processed locally
- Full transaction database stays on my machine
- Only monthly summaries (category totals) go to Google Sheets
- No third-party services with access to transaction details
2. Iterative Refinement
- Categorization rules improve over time
- New merchants added conversationally
- Edge cases documented and handled
3. Deep Insights
- Trends across months (not just current balance)
- Spending by group (Essential vs. Lifestyle)
- Top merchants (who am I actually paying?)
- Budget tracking (planned vs. actual)
4. Automation Without Lock-In
- Standard formats (JSONL, JSON)
- Open-source dashboard (MIT license)
- Portable (works on any machine with a browser)
Tools Used
- pdftotext — PDF extraction (command-line)
- Python — Parsing and categorization logic
- Chart.js — Interactive charts (via CDN)
- OpenClaw — Automation (cron jobs, Telegram integration)
- Google Drive API — Statement download
- OpenClaw — Pair programming partner
Lessons Learned
1. Statement formats change. Banks update their PDFs without warning. Build parsers defensively: validate extracted amounts, detect format changes, alert on failures.
2. Categorization is never “done.” New merchants appear every month. Build the system to handle unknowns gracefully: flag them for review, suggest categories, learn from corrections.
3. Conversation beats configuration. Instead of editing JSON files, I tell OpenClaw: “All taxi transactions should be Transport.” It updates the rules, re-categorizes, and confirms. Faster, less error-prone.
4. Privacy requires discipline.
Make it easy to keep data private: .gitignore blocks all transaction files, documentation reminds you never to commit real data, sample files use generic merchants.
5. Single-file dashboards are underrated.
No build step. No npm install. No server. Just open dashboard.html in a browser. When it works, it works forever.
Current Status
Built in two days (two focused 2-hour sessions), then backfilled 5 months of historical data (October 2025 - February 2026):
- 1,700+ transactions processed
- 100% categorization achieved
- Zero manual data entry
- Monthly automation running on schedule
Average time spent per month: ~10 minutes reviewing uncategorized transactions.
What’s Next
Planned enhancements:
- Budget tracking with alerts (notify when approaching limits)
- Predictive forecasting (estimate next month’s spend)
- Year-end tax summary (separate business expenses, charitable donations)
- Multi-currency support (track FX fees separately)
Maybe later:
- Mobile app (read-only dashboard access)
- Anomaly detection (flag unusual transactions)
- Cash flow projection (3-month lookahead)
Try It Yourself
The public repo includes:
- Complete dashboard (
dashboard.html) - Sample transaction data
- Category configuration example
- Setup instructions
Repo: https://github.com/czgroup/personal-spend-tracker
If you have bank statement PDFs and want visibility into your spending without giving third parties access to your accounts, start here.
Sometimes the best tool is the one you build yourself—especially when you have an AI assistant to pair program with.