Showing people why a payment was stopped, instead of asking them to trust that it was.
When a bank holds a payment you learn two things: that it was held, and that you should call someone. What tripped it stays inside the bank. Keystone is a payments app built around a fraud model that explains its own decisions. It started as a Human-Computer Interaction final with a team, and I rebuilt it on my own two years later as a working front-end shell, which is where most of what follows actually got tested.
Overview
Transparency, trust and control, in a flow where the model moves faster than the user.
The original concept had the right pieces: a security score, live alerts, biometric approval, and a model reading every transaction. It spent all of them on reassurance. Badges telling you that you were safe, which is the same black box in better packaging.
The questions I cared about were hard to answer in static frames. How much security presence is too much? Will anyone read five risk factors, or do they just want the verdict? So I rebuilt the thing as something you could use.
A payment sent, screened and approved. The prototype drives itself.
Open the working prototype ↗The calm path
Designing for the ninety-nine payments that are fine.
Almost every time, the model has nothing to say. Screening should cost the user a beat of reassurance and no more, so the send flow runs five steps on one thumb with no interruption. Four checks complete before the money moves and you never wait on them.
Screening is the one moment the product acts on a payment instead of carrying it, so it is the one screen that changes register. The interface drains to near-black and a ticked dial turns while the payment is read. Every other screen in the app has colour in it. This one has almost none.
The instrument, turning. Three of four checks set.
Reading the risk
Leading with the stop, then the evidence.
A held payment usually arrives as a wall of text. But nobody opens that screen wanting to know why. They want to know how bad it is, and what they are supposed to do about it. So the review opens on the stop itself: the amount, the merchant, and the fact that nothing has left the account yet. The evidence follows, five weighted signals in order of strength.
Unknown merchant 94, unusual amount 86, distant origin 62, off-pattern timing 34, device match 12.
THE DECISION
A hold narrows the choice without taking it. Both outcomes sit in a footer pinned to the bottom of the sheet, so the decision stays within thumb reach however long the signal list runs. “Yes, this was me” releases the payment and folds the merchant into what the model trusts. “Not me” freezes the card and states plainly that you carry no liability while it is reviewed.
Research
Twenty people, five questions, asked out loud on campus.
The original research was deliberately low-tech. We stopped twenty people across the Rutgers campuses, asked each of them the same five questions about paying online, and typed the answers into a shared sheet. We asked out loud instead of sending a form, because people qualify themselves when they speak in a way they will not when they type, and the qualifications turned out to be the useful part.
We grouped the answers on an affinity diagram under needs, wants and concerns. The concerns column set the brief. What people described was less a fear of fraud than a fear of being told nothing while it was sorted out.
THE TENSION IT LEFT US WITH
Security you cannot see does no reassuring. Security you always see becomes a checkpoint. I did not want to settle that by argument, so in the rebuild I made visibility a variable with three settings and had every screen answer to it.
01
Quiet
Present without announcing itself. No score, no trust block.
02
Default
What ships: the mark in the header, the stack in the feed.
03
Foregrounded
Something needs attention, so narration takes the top of the screen.
Default is what the build ships with. Enough that the model is visibly working, quiet enough that it is not asking for credit. Foregrounded earns its place in the minutes after a hold, when narration is genuinely wanted, and nowhere else.
Identity
The first build looked generated, so I threw the surface away.
Version one was obsidian with an iris-to-magenta gradient, glows on everything, and a radar chart in the middle of the risk review. Every one of those is a default, the thing you reach for before you have decided what the product is. It read as competent and anonymous, which for a security product is the worst tone available.
A keystone is the wedge at the apex of an arch that locks the other stones in place. Pull it and the structure comes down, which is close enough to how layered protections work that the identity could be literal. Six stones, one for each protection you have armed, with the keystone at the top. Five of six set means the keystone is still out, so nothing is locked. The score is not illustrated by the stack. It is the stack.
The mark assembles the way the object does, bottom stone first, then it holds.
THE SAME SYSTEM, ACROSS THE FLOW
Six screens in the order you meet them: the promise, the dashboard, the ledger, the screening, the held payment, the score. One ground, one rock, one typeface, and an instrument that only shows up where the product is doing something to a payment.
The score you can move
Making the number answer to something the user controls.
Trust scores in finance apps are handed down, with no visible relationship to anything you can change. Here the score is the sum of six protection weights. Switch one off and it recalculates in front of you, the stack loses a stone, and the crown stone starts to drift because the structure is no longer steady.
96 down to 64 as protections come off, then back up.
ONE SCHEME, NOT ONE ACCENT
The palette is a single object. A scheme owns the ground, the hero gradient, the screening instrument, the rock the stones are cut from, and every surface and semantic colour when it runs dark. Swapping only the accent, which is what the first version let you do, produces the same app with an odd button in it.
Engineering
Two problems I only found because the prototype was real enough to use.
The first build let the decision buttons sit at the end of the content. On a 390-point screen the signal list pushed them below the fold, which put the most important control in the product behind a scroll past every reason to distrust it. A sticky footer and a gradient fade fixed it. Both outcomes now sit pinned to the bottom of the sheet. In a static frame that screen looked finished.
The held payment, with the decision pinned under the signals.
A CHART THAT MEASURED NOTHING
The dashboard carried a line chart of payments screened per week. It looked like insight. What it actually plotted was how much the account had spent, which is the user’s own behaviour and carries no decision for them to make, and it repeated the strip forty pixels below it.
It is one mark per payment now, across four weeks, laid out by day so that busy days crowd and quiet ones leave gaps, with height standing in for the amount. You read it as texture. The only two marks carrying colour are the payment that was held and the one still being watched.
The prototype
Eleven screens you can actually walk through.
Three onboarding beats, four tabs and four overlay flows. It opens on the welcome screen and you use it the way you would use the app, with no rail, no control panel and nothing else around the device. I built it in React so the questions this project asks could be answered by using it.
EVERY COLOUR AND CORNER IS ONE TOKEN AWAY
No component in the build holds a literal colour or radius. A scheme writes all of them as CSS custom properties that the whole app reads, so changing one line re-tints the product end to end. That is how the palette got from plaster and sage to slate without a single screen being redrawn.
WHAT THE SHELL MADE POSSIBLE
01
Scripted reels, for the films on this page
Each film is a script of targets and captions that the prototype plays back to itself. A synthetic pointer travels to a control, taps it, and the narration runs underneath. The prototype ships without them, because a visitor should meet the app and not a workbench.
02
It records itself
A headless recorder drives those reels and captures real frames over the debugging protocol, so every film here is generated from the build. Change a screen, re-run one command, and the case study is current again.
03
Cards as objects
A physical card, a merchant-locked virtual number and a business card, each with its own freeze switch and spend meter.
Open the working prototype ↗Validation
What the build showed, and what it only asserts.
The finding that stuck: people will accept almost any safeguard once you tell them why it is there, and resent a small one when you do not. Every decision in the build follows from that. The stack you can move, the instrument that shows its working, the decision that stays on screen.
11
Screens, all navigable, in a shell rather than a clickthrough.
5
Signals behind every hold, each one weighted and shown.
0
Red walls. Every stop arrives with its reasons and both outcomes.
Reflection
What it has not earned yet.
1
The stack is a claim about legibility
I believe six stones read faster than a number, and that losing one reads as losing cover. That is a hypothesis. It needs five people and a stopwatch, not my confidence in it.
2
The dark scheme needs an accessibility pass
State is carried by colour, icon and text together, and I checked contrast by eye. It has not been through a screen reader, or tested past honouring the reduced-motion query.
3
The watching verdict needs a home
Recurring subscriptions sit between cleared and held, and that middle verdict currently gets a badge and one amber mark. It deserves a surface of its own.
4
Business mode is a switch, not a flow
Dual approval over a threshold is stated in the profile and implemented nowhere. It is the obvious next piece of work.
Up next
The rest of the work.