Skip to content

Instantly share code, notes, and snippets.

@shotasenga
Last active May 18, 2026 23:07
Show Gist options
  • Select an option

  • Save shotasenga/c461a672d9c9f927ce213a0c3e9e1895 to your computer and use it in GitHub Desktop.

Select an option

Save shotasenga/c461a672d9c9f927ce213a0c3e9e1895 to your computer and use it in GitHub Desktop.
Export transactions from Wealthsimple to a CSV file for YNAB import
// ==UserScript==
// @name Export Wealthsimple transactions to CSV for YNAB
// @namespace https://shotasenga.com/
// @version 2025080400
// @description Export transactions from Wealthsimple to a CSV file for YNAB import
// @author Shota Senga
// @match https://my.wealthsimple.com/app/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=wealthsimple.com
// @grant none
// ==/UserScript==
/*
* DISCLAIMER:
* This script extracts sensitive financial information (transaction data) from Wealthsimple.
* Ensure that you use this script in a secure environment and handle the extracted data responsibly.
* The developer of this script is not responsible for any issues or troubles that arise from its use.
*/
(function () {
"use strict";
waitUntilElementExists("//h1[contains(., 'Activity')]", (element) => {
const button = document.createElement("button");
button.innerText = "Export transactions";
button.onclick = exportTransactions;
element.parentElement.appendChild(button);
});
async function exportTransactions() {
const transactions = [];
for (const button of x(
`//button[contains(., 'Chequing')][contains(., '$')]`
)) {
const payee = button.querySelector("p").innerText;
const amount = x(`.//p[contains(., '$')]`, button).next().value
.innerText;
button.click();
await nextTick();
const [date, _] = Array.from(
x(
`.//p[contains(., 'Date')]/following-sibling::*//p`,
button.parentElement.parentElement
)
).map((el) => el.innerText);
transactions.push({
payee,
amount,
date: formatDateForYNAB(date),
});
}
const csv = [];
csv.push("Date, Payee, Amount");
for (const transaction of transactions) {
csv.push(
[transaction.date, transaction.payee, transaction.amount]
.map(escapeCsvField)
.join(",")
);
}
// save as a file
const blob = new Blob([csv.join("\n")], { type: "text/csv" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "transactions.csv";
a.click();
}
function* x(xpath, root = document) {
const xpathResult = document.evaluate(
xpath,
root,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null
);
for (let i = 0; i < xpathResult.snapshotLength; i++) {
yield xpathResult.snapshotItem(i);
}
}
function nextTick() {
return new Promise((resolve) => setTimeout(resolve, 0));
}
function waitUntilElementExists(xpath, callback) {
const observer = new MutationObserver(() => {
const element = x(xpath).next().value;
if (element) {
observer.disconnect();
callback(element);
}
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
});
}
function escapeCsvField(field) {
return `"${field}"`;
}
function formatDateForYNAB(str) {
// "August 19, 2024" to "2024-08-19" using RegExp
const [, month_s, day_s, year] = str.match(/(\w+) (\d+), (\d+)/);
const month = (new Date(Date.parse(`${month_s} 1, 2020`)).getMonth() + 1)
.toString()
.padStart(2, "0");
const day = day_s.padStart(2, "0");
return `${year}-${month}-${day}`;
}
})();
@mark05e

mark05e commented Feb 8, 2026 •

Copy link
Copy Markdown

Made updates to @kaipee's version over on my fork at https://gist.github.com/mark05e/4e8bcfa54df846529a0bd756c27f2222

  • Fixed "null date" errors by updating the date extraction XPath to traverse parent/sibling containers, ensuring compatibility with nested DOM structure.
  • Enhanced the Payee logic to automatically prepend the transaction type (e.g., "Purchase" or "Bill pay") and append the destination account (e.g., "Transfer out - RRSP") by extracting details from expanded transaction views.
  • Updated metadata with contributor Gist profiles and added downloadURL/updateURL to enable automatic script updates directly from the gist source.

@davidcollins5875-cmyk

Copy link
Copy Markdown

I think it would be helpful to include a link to Wealthyspeak
when discussing the wealth effect. It provides an excellent explanation of how changes in wealth impact consumer behaviour and fits well with the context of wealth and consumption.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment