How I Taught Bob to Download My Bank Statements
TLDR: I was tired of manually logging into three bank websites every month to download statements. So I figured out how to make Bob (my AI partner) do it for me by talking to the same behind-the-scenes system the bank’s own website uses. It worked, and the approach applies to basically any website that guards its data behind a login.
The ten minutes I couldn’t stand
Every month, same routine. Log into bank number one. Navigate to statements. Click download. Save the PDF. Repeat for bank number two. Bank number three. Ten minutes, tops.
But here’s the thing: I’d already built a system that reads those PDFs and automatically sorts my expenses into categories. The whole pipeline was hands-free, except for the very first step, where a human (me) has to click buttons in a browser like it’s 2005.
So I decided to cut myself out of the loop.
The secret door every bank leaves open
No Canadian bank offers a way for your own software to download your statements. There’s no official connection point. But here’s what I realized: every modern bank website is really just an app running inside your browser. When you click “download statement,” that app sends a request to a behind-the-scenes system, which sends back your data.
The bank built that system for their own website to use. But Bob can send the exact same requests. I’m not tricking anything or breaking in. I’m just knocking on the same door the bank’s own website knocks on, using the same key.
Think of it like a restaurant with no public phone number, but the waiters call the kitchen on a house phone to place orders. If you figure out the extension, you can call the kitchen yourself.
Why it’s harder than it sounds
Banks, understandably, don’t want robots logging in. They’ve built layers of protection.
First, there’s a bouncer at the door. Before you even see the login page, the website checks whether you’re a real person using a real browser. My first attempts just hung forever. The bank’s system saw a non-human visitor and simply refused to respond. Not an error, not a rejection. Just silence.
Then there’s the login itself. Card number on one page, password on another, then a verification code sent to my phone. Three separate steps, each depending on the last.
And finally, once you’re logged in, the website gets a digital pass that proves “this session is authenticated.” That pass is what you attach to every request. But the bank hides it in an unusual place. It’s not stored anywhere I could easily grab it. It lives only in the browser’s short-term memory, attached to requests as they fly out the door.
How I actually pulled it off
The approach has two parts.
First, I read the bank’s own website code. Every website ships its instruction manual right to your browser. It’s compressed and ugly, but it’s all there: every request the site makes, every address it talks to, every piece of data it expects. It’s like the restaurant printing its internal phone directory on the back of the menu in tiny font.
Second, I used a real browser (the only thing that gets past the bouncer) just long enough to log in. About thirty seconds. During that window, I watched the outgoing requests and grabbed the digital pass as it went by. Then I closed the browser and switched to a much faster, lighter approach for the actual downloads.
What surprised me
Every lesson came from something going wrong.
I locked myself out of my own bank account. Each failed login attempt counts against you. I was doing what any tinkerer would do: try something, see it fail, tweak, try again. Except each attempt required a new verification code sent to my phone, and after several abandoned attempts, the bank decided I was a fraud risk. Account locked. Lesson learned the hard way: you get very few shots at this. Build it right on paper first. Test once.
Sometimes there’s no login page. If a previous session left behind some data, the bank skips the login entirely and drops you straight onto the dashboard. My code expected the login page every time, so it just sat there, confused, staring at a dashboard it didn’t recognize. I had to build something smarter: look at where you actually landed, then figure out what to do next.
A tiny misunderstanding cost me way too long. One of my tools used a pattern-matching system that looked like one thing but worked like another. I wrote a pattern using rules I assumed applied, but the tool used different rules entirely. Everything just silently hung. No error, no clue.
What breaks and what doesn’t
Not everything is equally fragile. The behind-the-scenes system the bank uses? That almost never changes. Changing it would break their own mobile app. But the visual stuff, button labels, page layouts, the look and feel? That changes all the time.
So I built it so the fragile visual layer is thin and isolated. When the bank redesigns their login page, I update a few descriptions of what to click. The rest of the system doesn’t care.
What’s next
The first bank is fully automated. One command, and statements for the past seven years download themselves into the right folder, where my expense system picks them up automatically.
Two more banks to go. Same approach, different buttons to click.
The real discovery isn’t the script. It’s that this pattern works for almost any website that hides behind a login: healthcare portals, government services, school platforms. They all use the same architecture. Once you’ve figured out one, the next one is mostly just learning where the new buttons are.
Ten minutes a month isn’t much to save. But it’s one more thing I never have to think about again. And honestly? That’s the whole point.


