Two customers, one interface
upSWOT sells to banks; the people using it are the banks' small-business customers. The bank wants its own brand and a reason to be more than a payment account; the owner wants to know whether they can make payroll.
Compliance rules and data constraints define the product long before an interface does. The platform aggregates accounting, payroll, e-commerce, CRM and marketing data — over a hundred sources — into cash-flow forecasts, KPIs, valuation and a business credit score.
The bottleneck was styling
Customising the product for the first bank took six months. It was re-skinned by hand against a legacy front end, and every bank after it faced the same work again.
I replaced per-client styling with three token layers: Core holds primitives, Semantic holds intent, and a third set is one bank’s theme. A component may only reference the middle layer, so a bank supplies values into the third and never touches the first two. Re-theming stopped being a code change, and onboarding went from six months to two weeks.
What made this harder than normal theming is where the modules run: as web components inside somebody else’s online banking, in a page written by a bank’s vendor, sometimes a decade old. Four things go wrong there before a brand colour matters.
- The host stylesheet reaches in. A rule as ordinary as
.btnlands on our elements — a shadow root ends that. - Inheritance crosses the boundary anyway.
font-familyandcolorwalk straight through, so the boundary needs an explicit reset. - Custom properties cross it by design — the theming mechanism and the leak at once. Namespacing every internal token keeps a bank’s
--brandoff our buttons. - Overlays die in somebody else’s
overflow: hidden. They anchor out to the widget root, and the stacking budget is documented rather than discovered.
The rest of the contract was a table per component — what you can change, what you can’t, customisation options — so a bank’s identity arrived as values against a stated boundary, not a negotiation per onboarding.
The bank-side console
I redesigned the console banks work in: client portfolios, analytics, reporting, white-label customisation, insights, users and groups, settings. Dense screens for people who live in them all day.
The insight surfaces are where the two audiences meet. A card reports that a customer’s receivables aged past ninety days jumped nineteen per cent, and proposes factoring — the bank reads a lending trigger, the business reads a warning it would otherwise find late. Both readings come off the same row — copy that serves one side and merely tolerates the other picks a side.
The connected-accounts screen is built around Failed, Pending and Connected and a reconnect action, because the success metric was that customers shared their data — the states of that connection were the product. And every data module carries a freshness stamp in its chrome rather than inside its content, because for aggregated financial data “how old is this” is never optional.
Why people wouldn't connect their data
The product only works when a business connects its accounts and apps. In interviews it became clear they wouldn't — not for usability reasons, but because being asked by a bank to hand over the full picture of your business feels like being assessed, not helped.
Connection rate was the metric the company was raising against — and the research said it would never move through the bank channel.
So I pushed a different response: a direct-to-SMB product, CreditPush, where the benefit of sharing belongs to the owner — connect your systems, improve your credit score, get better financing terms. It had to be tested by shipping, because we had no direct access to the banks’ customers: the people whose behaviour decided the product sat behind the institution selling it to them.
The first customers connected their accounts and shared their data — the only evidence that counts, because the refusal being tested was a refusal to do exactly that.
That moved the valuation and opened a market the company had not been in: credit history built from a business’s own operational data. The interface work was competent; what moved the company was arguing against its own primary channel and being right.
Credit score improvement system
I designed the credit score improvement feature — score history over 3, 6 and 12 months, account overview with recommended limits and overdue balances, and the factors affecting the score with severity, which differ by bureau. The company filed it for U.S. patent protection.
Each factor carries its value and weight; because factors differ per bureau, the bureaus are tabs rather than a setting. The history view keeps the band legend beside it — without it, sixty is just a number.
The part I would defend hardest is the step before any of that. A bureau file is keyed to a legal entity, and an owner types the name they trade under from the address they moved to last year — so the first screen of the feature is not a score, it is an identity match against a third party’s database. The design work lives in the imperfect matches, and in answering the objection every owner has — does this hurt my score — inside the flow rather than in a help centre.
What the complete version of this page adds
- The two banks whose brands these screens wear, and the token sets behind the theming
- What the data-sharing finding was worth: the metric the round was raised against
- The early-access connect page as shipped, desktop and 320px, and the two slides from the deck of the time
- The patent application number, and the honest account of what became of it
- The credit score module at full page: five bureaus side by side, business and personal, and the bureau connection flow with every way an identity match goes sideways
It lives at alex.zhovnir.com/ua/work/upswot, behind a password — client agreements, not theatre. Send me a note and I’ll open it: alex@zhovnir.com.