How To Create A Fullstack Bank Statement Visualization App

Table of contents

Proper tracking of monetary flows is always helpful in personal finance. I participated in a recent hackathon where I built an MVP that users can utilize in visualizing their bank statements.
This blog is a break-down of this feature. You’ll learn how you can also build the same with Python for backend and Nextjs for frontend.
Interestingly, you’ll learn how to use some python libraries for data visualization, which are quite impressive.
Building the Backend
Let’s write our backend with Python. You can create a folder, and then a file called app.py
for the program.
Step 1: Dependency Installation
Head to your terminal and install .
pip install Flask Flask-CORS
Step 2: Import Dependencies
Once these deps are installed via the terminal, they should also be imported into the program.
from flask import Flask, request, jsonify
from flask_cors import CORS
import re
from collections import Counter
These are important libraries in our application.
For those who are not aware, Flask is a web framework for Python applications. In the instant case, it will be useful for building our API routes and connecting them with the web successfully.
We will also be using Request, a native Python library for efficient HTTP interaction. It will be useful for accepting data from API routes that are sending information.
Along this line, Jsonify helps us in communicating back to the API we will create so our frontend and backend can communicate effectively well.
Now, you should bear in mind that we want our API to be accessible from any point, and this is where Cross-Origin-Resource Sharing becomes useful. By the way, browsers block this to checkmate security threats, but we are enabling it intentionally for what we want to do.
Moving on to Re and Counter, their main purposes is largely for pattern matching.
Step 3: App Initialization
This is where we initialize our Flask application where name
is passed as the root path. Then we enabled CORS.
app = Flask(__name__)
CORS(app)
Step 4: Transaction Extraction
This function helps us extract the data we need from the provided bank statements. The sample bank statement we have has “send to” and “received from” pre-fixes for fund flows.
As a result, we are incorporating that into our program for easier catching. We created an POST API route for it called /paste
.
def extract_transactions(text):
sent_names = re.findall(r'Send to ([A-Z\s-]+)', text, re.IGNORECASE)
sent_counts = Counter(sent_names)
received_names = re.findall(r'Received from ([A-Z\s-]+)', text, re.IGNORECASE)
received_counts = Counter(received_names)
sent_data = [{'name': name, 'value': count} for name, count in sent_counts.items()]
received_data = [{'name': name, 'value': count} for name, count in received_counts.items()]
return sent_data, received_data
@app.route('/paste', methods=['POST'])
Step 5: Paste Transaction
Now, many bank statements have various formats of pdf and formatting that our program might not catch. Therefore, it is better to request customers paste their statements rather than upload them.
On this note, here is a function that does that.
def paste():
data = request.get_json()
transactions = data.get('transactions', '')
sent_data, received_data = extract_transactions(transactions)
return jsonify({'sent': sent_data, 'received': received_data})
if __name__ == '__main__':
app.run(debug=True)
Immediately after declaring the function, we also ran the application.
Here is the full code:
from flask import Flask, request, jsonify
from flask_cors import CORS
import re
from collections import Counter
app = Flask(__name__)
CORS(app)
def extract_transactions(text):
sent_names = re.findall(r'Send to ([A-Z\s-]+)', text, re.IGNORECASE)
sent_counts = Counter(sent_names)
received_names = re.findall(r'Received from ([A-Z\s-]+)', text, re.IGNORECASE)
received_counts = Counter(received_names)
sent_data = [{'name': name, 'value': count} for name, count in sent_counts.items()]
received_data = [{'name': name, 'value': count} for name, count in received_counts.items()]
return sent_data, received_data
@app.route('/paste', methods=['POST'])
def paste():
data = request.get_json()
transactions = data.get('transactions', '')
sent_data, received_data = extract_transactions(transactions)
return jsonify({'sent': sent_data, 'received': received_data})
if __name__ == '__main__':
app.run(debug=True)
Creating the Pie Component
Add a PieCharts.js
component. Here is the first slice of our frontend part.
Step 1: Initialize Nextjs
Run this in your terminal:
npx create-next-app@latest my-next-app
Step 2: Install Recharts
We have to install Recharts for our pie data representation:
npm install recharts
Step 3: Chart UI
The stage is set to build our pie-chart UI:
import { PieChart, Pie, Cell, Tooltip } from "recharts";
const COLORS = ["#ff4d4d", "#4d79ff", "#ffcc00", "#33cc33", "#ff66b2", "#9966ff"];
export default function CustomPieChart({ title, data }) {
return (
<div className="chart-box">
<h2>{title}</h2>
<PieChart width={500} height={500}>
<Pie
data={data}
cx="50%"
cy="50%"
outerRadius={200}
dataKey="value"
label={({ name, percent }) => `${name} (${(percent * 100).toFixed(1)}%)`}
>
{data.map((_, index) => (
<Cell key={index} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<Tooltip />
</PieChart>
</div>
);
}
In the code above, we installed the necessary things we need from recharts, then set the colors and layout of our application.
Here is the full code:
import { PieChart, Pie, Cell, Tooltip } from "recharts";
const COLORS = ["#ff4d4d", "#4d79ff", "#ffcc00", "#33cc33", "#ff66b2", "#9966ff"];
export default function CustomPieChart({ title, data }) {
return (
<div className="chart-box">
<h2>{title}</h2>
<PieChart width={500} height={500}>
<Pie
data={data}
cx="50%"
cy="50%"
outerRadius={200}
dataKey="value"
label={({ name, percent }) => `${name} (${(percent * 100).toFixed(1)}%)`}
>
{data.map((_, index) => (
<Cell key={index} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<Tooltip />
</PieChart>
</div>
);
}
Transaction Pasteing Interface
Create a PasteBankStatement.js
page. You can paste this code:
import React, { useState } from 'react';
import CustomPieChart from '../components/PieCharts';
import styles from '../styles/PasteBankStatement.module.css';
const PasteBankStatement = () => {
const [bankStatement, setBankStatement] = useState('');
const [sentData, setSentData] = useState(null);
const [receivedData, setReceivedData] = useState(null);
const handleSubmit = async (event) => {
event.preventDefault();
const response = await fetch('/api/paste', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ transactions: bankStatement }),
});
if (response.ok) {
const data = await response.json();
setSentData(data.sent);
setReceivedData(data.received);
} else {
const errorText = await response.text();
console.error('Error:', errorText);
}
};
return (
<div className={styles.container}>
<header className={styles.header}>
<h1>Paste Your Bank Statement</h1>
</header>
<div className={styles.card}>
<form onSubmit={handleSubmit} className={styles.form}>
<textarea
value={bankStatement}
onChange={(e) => setBankStatement(e.target.value)}
className={styles.textarea}
placeholder="Paste your bank statement here..."
required
/>
<button type="submit" className={styles.submitButton}>
Visualize
</button>
</form>
<div className={styles.chartsContainer}>
{sentData && (
<div className={styles.chartBox}>
<CustomPieChart title="Money Sent (Expenses)" data={sentData} />
</div>
)}
{receivedData && (
<div className={styles.chartBox}>
<CustomPieChart title="Money Received (Income)" data={receivedData} />
</div>
)}
</div>
</div>
</div>
);
};
export default PasteBankStatement;
Here is a brief rundown of what went on here:
importing the right libraries
linking API routes
handling the submit button
Demo
Run both the Python application and Nextjs program. Open your localhost, then paste this sample bank statement.
You should have something like this:
That’s it! Leave a comment if you find it helpful…
Subscribe to my newsletter
Read articles from John Fáwọlé directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

John Fáwọlé
John Fáwọlé
Web3 Technical Writer | Content Lead | Marketing Strategist | For Devs