DEV Community

Cover image for Adding live sync to a Notion finance template without Zapier, Make, or a backend published: false
Balaji K
Balaji K

Posted on

Adding live sync to a Notion finance template without Zapier, Make, or a backend published: false

How I turned WealthOS Lite into WealthOS Pro: a local-first Notion portfolio tracker with double-click sync for prices, SIP dates, and alerts.

tags: notion, javascript, productivity, showdev

A few weeks ago I wrote about shipping WealthOS Lite: a free Notion finance template that intentionally did less.

Two databases. A few formulas. No scripts. No API keys. No setup ceremony.

That post was about restraint.

This one is about the thing I deliberately left out of Lite:

live sync.

Most Notion finance templates run into the same wall eventually.

Manual tracking is clean, but stale.

Automation is useful, but the usual answer is:

  • connect Make.com
  • connect Zapier
  • pay monthly
  • create a bunch of scenarios
  • hope the integration does not break

That did not feel right for a personal finance system.

So for the Pro version, I tried a different architecture:

Keep Notion as the interface.

Keep the data in the user's workspace.

Run the sync locally on the user's own machine.

No hosted backend.

No Zapier.

No Make.

No subscription automation layer.

Just Notion + a small local Node.js sync app.

The constraint

I wanted WealthOS Pro to support a more complete portfolio:

  • stocks
  • mutual funds
  • ETFs
  • fixed deposits
  • gold
  • government bonds
  • retirement accounts
  • share plans
  • real estate
  • insurance
  • loans
  • financial goals
  • tax savings
  • alerts and reminders

But I did not want to turn it into a SaaS product.

That meant no central server storing user data.

The sync app had to run locally.

The user flow needed to be simple enough for non-developers:

1. Download ZIP
2. Duplicate Notion template
3. Double-click launch.command or launch.bat
4. Complete browser setup
5. Click Run Sync
No terminal commands.

That last part mattered more than I expected.

As developers, we are very comfortable saying:

node wealthos-sync.mjs
For normal users, that is already too much.

So the real product was not the script.

The product was making the script disappear.

The architecture
At a high level, WealthOS Pro looks like this:

WealthOS Notion Workspace
        |
        |  Notion API
        |
Local Sync App
        |
        |-- Yahoo Finance
        |-- Finnhub
        |-- mfapi.in
        |-- gold-api.com
The local app is a small Node.js bundle.

It reads a local .env file:

NOTION_API_KEY=...
MASTER_PORTFOLIO_ID=...
FINNHUB_KEY=...
Then it updates the Notion databases directly.

The important part: the data does not pass through my server.

There is no WealthOS cloud.

The user's portfolio lives in Notion, and the sync process runs on their computer.

Why not just build a SaaS?
I considered it.

A SaaS would be easier to monetize, easier to update centrally, and easier to control.

But personal finance data has a different trust profile.

I did not want users to ask:

Where is my portfolio data stored?

The answer should be simple:

In your Notion workspace and on your own machine.

That is also why the sync bundle is inspectable. The user can open the files, read the code, and see what is happening.

For this product, local-first felt more honest.

The single source of truth
The core Notion database is called Master Portfolio.

Every holding goes there.

Stocks, mutual funds, deposits, gold, loans, insurance, retirement accounts, share plans — all of them are rows in the same database.

That gives the system one reliable model:

Master Portfolio
├── Asset Name
├── Category
├── Sub-type
├── Country
├── Ticker
├── Units / Qty
├── Buy Price
├── Invested Amount
├── Current Price
├── Current Value
├── Gain / Loss
├── Return %
├── CAGR %
├── Next SIP Date
├── Last Updated
└── Risk Level
Different pages in Notion are just linked views of the same source.

That design decision avoided a trap I see in many complex Notion templates:

too many duplicated summary databases.

If you update one holding, every linked view, chart, formula, and dashboard can reflect it.

The sync app only needs to update the source rows.

How price sync works
For each row, the sync script checks the category and ticker.

For example:

NSE:RELIANCE  -> RELIANCE.NS
LSE:SHEL      -> SHEL.L
PA:MC         -> MC.PA
US stocks can use Finnhub if the user provides a free key.

Non-US stocks can fall back to Yahoo Finance.

Indian mutual funds use mfapi.in.

Gold uses a public gold price API.

The update is intentionally boring:

Enter fullscreen mode Exit fullscreen mode

const props = {
"Current Price": { number: result.price },
"Last Updated": { date: { start: new Date().toISOString() } },
};

if (result.change != null) {
props["Day Change %"] = { number: result.change };
}

await updatePage(row.id, props);

The sync app does not try to own the portfolio logic.

It just updates the few fields that should come from external data.

Notion formulas handle the rest.

The double-click launcher
This was surprisingly important.

The folder contains:

launch.command   // macOS
launch.bat       // Windows
install-node.html
setup-ui.html
wealthos-app.mjs
wealthos-sync.mjs
sync-portfolio-metrics.mjs
sync-sip-dates.mjs
sync-alerts.mjs
On macOS, users double-click:

launch.command
On Windows:

launch.bat
The launcher checks whether Node.js is installed.

If not, it opens a local install guide.

If yes, it starts the local web setup app.

That web app opens in the browser and walks the user through:

Notion integration token
Master Portfolio database ID
optional Finnhub API key
first sync
The goal was to make the developer workflow feel like a normal desktop app.

The part that broke during testing
One bug showed up late.

Prices worked.

Portfolio metrics worked.

SIP dates worked.

But alerts were skipped.

The output looked like this:

Refreshing Alerts & Reminders…
Missing NOTION_API_KEY, MASTER_PORTFOLIO_ID, or ALERTS_REMINDERS_ID

Sync Complete
Prices: 12 updated
Metrics: refreshed
SIP dates: refreshed
Alerts: skipped
The bug was not in the Notion API.

It was in the product assumption.

The setup UI told users:

Other databases are auto-discovered.

But sync-alerts.mjs still required ALERTS_REMINDERS_ID.

That mismatch is exactly the kind of thing that only appears when you test like a buyer.

The fix was to let the alerts sync search for the database by title:

Enter fullscreen mode Exit fullscreen mode

async function searchDatabaseByTitle(title) {
let cursor;
const wanted = title.toLowerCase();

do {
const body = {
query: title,
page_size: 100,
filter: { property: "object", value: "database" },
};

if (cursor) body.start_cursor = cursor;

const data = await api("POST", "/search", body);
const exact = data.results.find(
  (r) => titleOfDatabase(r).toLowerCase() === wanted
);

if (exact) return exact.id;

cursor = data.has_more ? data.next_cursor : null;
Enter fullscreen mode Exit fullscreen mode

} while (cursor);

return null;
}



Now the sync auto-discovers:

Alerts & Reminders
Insurance Policies
Then it saves those IDs locally for future runs.

That turned this:

Alerts: skipped
into this:

Alerts: refreshed
Small fix, big confidence boost.

What the sync updates
One sync run refreshes:

stock prices
mutual fund NAVs
gold prices
portfolio metrics
next SIP dates
alerts for SIPs
loan EMI reminders
maturity reminders
insurance renewal reminders
The final output looks like this:

Sync Complete

Prices:     12 updated, 1 skipped, 0 failed
Metrics:    refreshed
SIP dates:  refreshed
Alerts:     refreshed
Time:       93.7s
That “boring” summary is the whole point.

A user should not need to understand the internals.

They should just know the data refreshed.

Why I kept it zero-dependency
The sync bundle uses Node.js 18+ and native fetch.

No npm install.

No package manager.

No dependency tree.

That was intentional.

For a developer tool, dependencies are normal.

For a ZIP file that a customer downloads and double-clicks, every dependency is another support ticket waiting to happen.

So the constraint became:

Can this run with only Node.js installed?
That made the code a little more manual in places, but the install story became much cleaner.

What I learned
1. Automation has to feel calm
The user does not care that the Notion API call succeeded.

They care that their dashboard now looks updated.

2. Local-first is a product feature
For finance tools, privacy is not just a technical detail. It is part of the value proposition.

3. Notion is great as the interface layer
I did not need to build dashboards, tables, filters, and charts from scratch. Notion already does that well.

The local app only fills the gaps Notion cannot handle alone.

4. Testing the ZIP matters
Running the code from the repo is not enough.

The real test is:

download ZIP
extract ZIP
double-click launcher
follow setup
run sync
check Notion
That is where the product actually exists.

Where this fits
WealthOS Lite is still the best starting point if you want a simple free finance tracker inside Notion.

WealthOS Pro is for people who want the bigger system:

more asset classes
local sync
setup guide
videos
alerts
multi-country portfolio structure

I packaged the Pro version here:

WealthOS Pro - Automated Notion Portfolio Tracker

🚀 LAUNCH PRICE: $19 (regular price $29). First 100 buyers only.The Notion finance template you can actually automate.Most Notion finance templates either stop at manual tracking or ask you to bolt on recurring tools like Make.com or Zapier. WealthOS Pro gives you the useful middle ground: a polished Notion portfolio system plus an optional double-click sync app that runs on your own computer with no subscription layer in between.Extract the ZIP, double-click one file, complete a 4-step browser wizard, and refresh prices, NAVs, gold, SIP dates, portfolio metrics, and your alerts calendar whenever you want.Built by Bala, the engineer behind the open-source myFinance project. WealthOS Pro is the Notion version of the same local-first idea: your data stays in Notion, the sync runs on your machine, and the code is open for inspection.One dashboard for allocation, invested vs current, net worth, and SIP commitments.⚡ The killer feature - double-click sync, no terminal Extract the ZIP Double-click launch.command on macOS or launch.bat on Windows Complete the 4-step browser wizard Click Run Sync Every sync refreshes: Stock prices Mutual fund NAVs Gold prices Portfolio Metrics for the Invested-vs-Current chart Next SIP Date for active SIPs Alerts & Reminders for SIPs, loan EMIs, maturities, and insurance renewals No Node.js yet? The launcher detects that and opens a branded install guide with one download button and clear next steps.Prefer to inspect the code first? You can. The sync bundle is MIT-licensed, uses zero npm dependencies, and runs locally on your own computer.SETUP VIDEOS:SCREENSHOT:Double-click the launcher, complete the wizard, and run your first sync from the browser.📊 What you get 12 portfolio modules Retirement Deposits Gold Government Bonds & Schemes Stocks Mutual Funds Share Plans Real Estate Insurance Loans Budget Dashboard Planning and tracking extras Financial Goals tracker Tax Savings tracker Monthly Net Worth tracker Retirement Calculator Net Worth Milestones Alerts & Reminders calendar Supported asset coverage Stocks, ETFs, mutual funds, fixed deposits, recurring deposits Physical gold, sovereign gold bonds, gold ETFs Government schemes and bonds Real estate and REITs ESPP, RSU, ESOP, BSPCE, Sharesave/SAYE plans Insurance policies and loan tracking 🌍 4 country presets - ready on day one Country Examples includedIndia EPF, PPF, NPS, ELSS, SSY, KVP, SGBUS 401(k), IRA, HSA, I-Bonds, Treasury BillsUK ISA, SIPP, NS&I Premium BondsFrance PEA, Assurance Vie, Livret A, PERCountry-prefixed dropdowns make it easier to pick the right subtype, insurance type, or tax section without rebuilding the template yourself.🗂️ Architecture - one source of truth Every holding lives in one database: Master Portfolio. Risk Level is auto-tagged by category SIP fields live directly on each holding Linked module pages show the right slice of the same portfolio 13 chart views read from the core data model instead of requiring extra manual summary tables Update one row once, and the related totals, formulas, and views update with it That single-source-of-truth design is what keeps the template flexible instead of turning into a maze of duplicate databases.Master Portfolio is the single source of truth for holdings, formulas, and linked views.📅 One-spot due-date calendar Each sync rebuilds the auto-generated side of Alerts & Reminders with: Upcoming SIP execution dates Loan EMI dates Deposit, bond, and SGB maturities Insurance renewals Manual reminders you add are preserved alongside the generated ones.One reminders view for SIP dates, loan EMIs, maturities, and insurance renewals.🧮 Auto-calculated formulas Gain/Loss Return % CAGR Deposit maturity value with quarterly compounding Days to maturity and status badges EMI and total loan interest Annual SIP Risk Level Next SIP Date, maintained as a native date field for calendar compatibility 📈 13 pre-built chart views Allocation donut, net-worth growth, Invested-vs-Current bars, Risk distribution, Spending breakdown, Monthly income vs expense, Goal progress, Deposit maturity, Loan EMI comparison, Mutual fund returns, Stock holdings, Sector allocation, and Insurance coverage.Important Notion note: chart views require a paid Notion plan such as Plus, Business, or Enterprise. Everything else in WealthOS Pro works on Notion Free: the core databases, formulas, linked views, the SSOT Master Portfolio, alerts calendar, and the sync app.🆚 WealthOS Pro vs the usual alternatives 📦 What's in your download Your WealthOS-Pro.zip includes: launch.command - macOS launcher launch.bat - Windows launcher install-node.html - branded Node.js install guide setup-ui.html - browser wizard UI wealthos-app.mjs - local app server wealthos-sync.mjs - main sync engine sync-portfolio-metrics.mjs sync-sip-dates.mjs sync-alerts.mjs .env.example README.txt Delivered with the purchase: Notion template duplicate link Complete setup guide PDF with screenshots Lifetime updates Priority email support ✅ Requirements A Notion account A computer running macOS, Windows, or Linux Node.js 18+ for the optional sync app A free Notion integration token Optional: a free Finnhub key for real-time US stock prices. Yahoo Finance is used as the fallback for delayed non-US pricing. The Notion template itself works without the sync app. If you prefer, you can use it entirely manually and still get the databases, formulas, views, and planning structure.👨‍💻 Who made this I'm Bala, a senior software engineer with 12+ years of experience building production software, automation infrastructure, and API testing systems.I built WealthOS for my own portfolio after years of trying spreadsheets and dashboard subscriptions. The open-source myFinance project came first; WealthOS Pro turns the same local-first philosophy into a more complete Notion workflow.🚀 Launch price $19 for the first 100 buyers. After that, the price becomes $29.Every buyer gets lifetime updates at no extra cost. Bala @buildwithbalaji

favicon balajibuilder.gumroad.com

The original open-source single-file finance app is here:

GitHub logo balajiregt / myFinance

Self-hosted, single-file Indian portfolio tracker with AI insights, Gmail expense tracking

₹ FinFolio — Complete Indian Portfolio Tracker

Self-hosted, single-file, privacy-first portfolio tracker for Indian investors.

Track Stocks, Mutual Funds, FDs, RDs, SGB Gold, Physical Gold, Post Office schemes, Retirement (EPF/NPS), Real Estate, Insurance, Loans, Company Share Plans (ESPP/RSU/ESOP), and more — all from one dashboard with AI-powered insights. Auto-track expenses from bank emails via Gmail API. Proactive alerts via Telegram/WhatsApp.

Self-hosted means YOU own it. Fork this repo. Run it locally, or deploy to your own Fly.io instance. Cloud backup goes to your own Supabase instance. All data stays in your browser by default — no shared servers, no tracking, no accounts.


Why FinFolio?






















Problem FinFolio Solution
Groww/Zerodha only show what you buy through them Tracks ALL assets — broker, manual, physical
INDMoney wants your bank login Zero server-side data — 100% localStorage
No app tracks physical gold in your bank locker Physical gold tracker with storage locations + photo




And the earlier post about shipping WealthOS Lite is here:

Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
markusbnet profile image
Mark Barnett

The no-backend constraint is interesting. How are you handling conflict resolution when edits happen on multiple devices? Personal finance tools have a unique challenge where even small sync bugs erode trust fast — if a transaction goes missing, you question the whole system.

Collapse
 
buildwithbalaji profile image
Balaji K

hi Mark, thanks for your time and for raising this query.
The thing is wealthOS intentionally avoids being a transaction ledger.

Notion stays the source of truth for user-entered holdings.
The local sync only updates derived/market fields like current price, day change %, last updated, next SIP date, and auto generated alerts.

So theres no multidevice merge logic for transactions.
User owned fields follow notion’s sync model..sync owned fields are safely overwritten on refresh.

Hope that answers your query.