Skip to content

Instantly share code, notes, and snippets.

@shotasenga
Last active March 4, 2025 19:04
Show Gist options
  • Save shotasenga/c461a672d9c9f927ce213a0c3e9e1895 to your computer and use it in GitHub Desktop.
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 2024090300
// @description Export transactions from Wealthsimple to a CSV file for YNAB import
// @author Shota Senga
// @match https://my.wealthsimple.com/app/activity*
// @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(., 'Cash')][contains(., 'CAD')]`
)) {
const payee = button.querySelector("p").innerText;
const amount = x(`.//p[contains(., 'CAD')]`, 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}`;
}
})();
@shotasenga
Copy link
Author

Instruction

  1. Install Tampermonkey https://www.tampermonkey.net/
  2. Open the raw script link to install

Once you install the script, open the "Activity" page in your browser. The "Export Transaction" button should appear on top-right.

Screenshot 2024-08-31 at 3 51 22 PM

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.

@shotasenga
Copy link
Author

I've created a bookmarklet version of this so you can run it on any browsers without installing an extension.

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