Skip to content

Instantly share code, notes, and snippets.

@weiserr
Last active December 23, 2025 15:57
Show Gist options
  • Select an option

  • Save weiserr/bc0745d3145b29f02b1d to your computer and use it in GitHub Desktop.

Select an option

Save weiserr/bc0745d3145b29f02b1d to your computer and use it in GitHub Desktop.
Postfinance YNAB Export

PostFinance YNAB 4 Export

This scripts allows the export of PostFinance account flow data for YNAB 4 using Tampermonkey. The export is not based on the CSV generated by the Post as it does not adhere to the standard but makes use of the data loaded on the client side for doing said CSV export.

Installation

If Tampermonkey is installed you can click on the RAW view of the postfinance-ynab.user.js file of this Gist. Tampermonkey should ask you whether or not you would like to install this script.

Usage

Tip: if you have a lot of transactions make sure to increase the shown amount from 25 to 100 somewhere in the settings.

Navigate to the account flow data in PostFinance (Konto -> Bewegungen) and:

  1. Click on the YNAB Export button.
  2. Hit the import button in the YNAB account view.
// ==UserScript==
// @name Postfinance CSV Export
// @namespace http://death-knight.com
// @include https://www.postfinance.ch/ap/ra/ob/html/finance/*
// @updateURL https://gist.github.com/weiserr/bc0745d3145b29f02b1d/raw/postfinance-ynab.user.js
// @downloadURL https://gist.github.com/weiserr/bc0745d3145b29f02b1d/raw/postfinance-ynab.user.js
// @version 16
// @grant none
// ==/UserScript==
// Function definitions
function createGenerateButton() {
let input = document.createElement("button");
input.type = "button";
input.className = "ynab-button appearance-none before:absolute before:bg-inherit before:border before:border-inherit before:disabled:opacity-0 before:duration-150 before:ease-in-out before:hover:opacity-100 before:inset-[-3px] before:opacity-0 before:rounded-max before:transform before:transition-opacity before:z-[-1] bg-fpui-button-primary-background-color border border-fpui-button-primary-border-color border-solid cc-text-sm disabled:bg-fpui-button-primary-background-disabled-color disabled:border-fpui-button-primary-border-disabled-color disabled:text-fpui-button-primary-text-disabled-color fpui-button gap-2 h-13 inline-flex items-center leading-none p-3 place-content-center place-items-center relative rounded-max sm:w-auto text-center text-fpui-button-primary-text-color w-full xs:px-8 xs:py-4 z-0";
input.textContent = "YNAB Export";
input.onclick = createExportButton;
document.querySelectorAll('fpui-actions').forEach(elem => {if(elem.querySelectorAll(".ynab-button").length < 1) {elem.appendChild(input)}});
}
function createExportButton() {
const csv = createCSV();
const date = new Date();
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const filename = "ynab-" + year + "-" + month + "-" + day + ".csv";
// create a temporary download link
let input = document.createElement("a");
input.setAttribute('href', 'data:text/csv;charset=UTF-8,' + encodeURIComponent(csv));
input.setAttribute('download', filename);
input.style.display = 'none';
// ...and click it to trigger the download
document.body.appendChild(input);
input.click();
document.body.removeChild(input);
}
function createCSV() {
// acquire the data computed by the Post
const rows = Array.from(document.querySelector('[data-cy="movements-table"] > tbody').querySelectorAll("tr"));
// process the content
let result = rows.map((row, index) => sanitizeRow(row));
// add the header
result.unshift(createHeader());
// join the results into a single string
return result.join("\n");
}
function createHeader() {
return 'Date,Payee,Category,Memo,Outflow,Inflow';
}
function sanitizeRow(row) {
const date = row.querySelector('[data-cy="date"] > span:nth-child(2)').textContent;
const payee = row.querySelector('[data-cy="shortText"] > span:nth-child(2)').textContent.replace(/\"/gi, '').replace(/\n/gi, ' ').replace(/,/gi, '; ').trim();
const category = '';
const memo = '';
const outflow = row.querySelector('[data-cy="debit"] fpui-amount > span:nth-child(1)')?.textContent?.replace(/[^\d\.]/g, '')?.trim() ?? '';
const inflow = row.querySelector('[data-cy="credit"] fpui-amount > span:nth-child(1)')?.textContent?.replace(/[^\d\.]/g, '')?.trim() ?? '';
let line = [];
line.push(date);
line.push(payee);
line.push(category);
line.push(memo);
line.push(outflow);
line.push(inflow);
return line.join(',');
}
function waitForElem(selector) {
if (document.URL == "https://www.postfinance.ch/ap/ra/ob/html/finance/assets/movements-overview" && document.querySelector(selector)) {
createGenerateButton();
}
const observer = new MutationObserver((mutations) => {
if (document.URL == "https://www.postfinance.ch/ap/ra/ob/html/finance/assets/movements-overview" && document.querySelector(selector)) {
createGenerateButton();
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
}
waitForElem('fpui-actions');
@weiserr
Copy link
Author

weiserr commented Feb 22, 2025

Minor update due to the following:

  • Previously we had to skip over the first entry of the transaction table body due the header information being encoded in the first row (not apparent in the UI but in the HTML). As the table now follows HTML semantics - the header information is not part of the body anymore - we are not skipping over the first entry anymore but correctly exporting all transactions.

@weiserr
Copy link
Author

weiserr commented May 13, 2025

Minor update due to the following:

  • change in the URL from https://www.postfinance.ch/ap/ba/... to https://www.postfinance.ch/ap/ra/...

@weiserr
Copy link
Author

weiserr commented Dec 23, 2025

Minor update due to the following:

  • the nesting of the credit and debit values has been adapted
  • apparently the styling is now being done with a CSS utility library like e.g. Tailwind

@weiserr
Copy link
Author

weiserr commented Dec 23, 2025

Haha - finally after roughly 10 years the naming on the button is fixed - adapted from "YNAP" to "YNAB"...

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