Skip to content
../projects

Case study

Payments

Getting Customers Through TrueLayer's Consent Flow

A third of customers who chose pay by bank never finished paying, and most of them were lost inside their own bank's login. App-to-app redirects, a QR hand-off on desktop, a smarter bank picker and a return page that survives a lost session took completion from 64% to 82%.

Visit the live site
Naseebullah AhmadiSenior Software Engineer, London
  • 4 min read
  • Duration2 yrs 7 mos
  • Last updated

The impact, in numbers

Payment completion
64% → 82%
Customers who chose pay by bank and got back to the merchant.
Authorised once at the bank
81% → 91%
App-to-app and the desktop QR hand-off, mostly.
Data connections lapsing at 90 days
~33% → <10%
After reconfirmation moved into one in-app prompt.

Context

I was one of the engineers on the team that owned TrueLayer's hosted consent journey: the pages between a merchant's "Pay by bank" button and the customer's bank. It covered bank selection, the consent screen, the redirect out to the bank and the page the customer came back to, built in #react and #typescript. The same journey also connected accounts for data access, which customers had to renew every 90 days.

The constraint

Each payment crossed three owners. The merchant owned the checkout, we owned selection and consent, and the bank owned login and authorisation. The biggest losses happened on the bank's side, where we couldn't change a single screen.

The consent screen was regulated, so content couldn't simply be cut: the Customer Experience Guidelines set what it must show. And money was moving. A return page that recorded a payment because a customer reached it, or a retry that sent a second consent, could charge someone twice.

What I did

  1. Merchant checkout to Bank picker + consent
  2. Bank picker + consent to Bank's app: Universal / app link
  3. Bank picker + consent to Bank web login: Fallback only
  4. Bank picker + consent to Desktop: QR code: On desktop
  5. Desktop: QR code to Bank's app: Scan
  6. Bank's app to Return page, no session: Redirect back
  7. Return page, no session to Payment status + webhook: Look up by payment ID
Every hand-off between merchant, provider and bank, and the two routes into the bank's app
  1. 1

    Measure across the bank boundary

    We couldn't see inside the bank, so I tracked the redirect out and the return in with #mixpanel, joined them to the payment's final status, and broke it down per bank. That showed the bank's login, not our screens, losing the most.

  2. 2

    Rebuild the bank picker

    Ordered by our own payment volume instead of alphabetically, with search that knows aliases ("RBS") and a single "Continue with" button for the last bank used on that device.

  3. 3

    Warn about bank outages before the redirect

    Surfaced each bank's live status on the picker, so a customer whose bank was down heard it from us, not from a failed login.

  4. 4

    Trim the consent screen to what's required

    Payee, amount, reference and one "Continue" button, with the terms one tap away instead of a wall of text above the button.

  5. 5

    App-to-app on mobile

    Handed off through each bank's universal or app link, so customers approved in their banking app with Face ID instead of hunting for web credentials they had never used.

  6. 6

    A way out of in-app browsers

    Links opened from social apps run in a built-in browser where universal links often don't fire. I detected that case and showed an explicit "Open in your banking app" button.

  7. 7

    QR hand-off on desktop

    Instead of the bank's web login, desktop showed a QR code that opened the same consent on the customer's phone, while the desktop tab waited for the result.

  8. 8

    A return page that needs no session

    The bank's app often reopened the return URL in a different browser, without the merchant's cookie. The page now looks up an unguessable payment ID and shows only the status; the merchant's records come from the webhook, never from this page loading.

  9. 9

    One-tap 90-day reconfirmation

    Once the FCA's PS21/19 let providers reconfirm data access instead of sending customers back through their bank, I built an in-app prompt shown a week before expiry, listing what the customer would keep sharing.

  10. 10

    Considered: our own bank login screen

    Rejected. Collecting bank credentials on a third-party page is screen scraping, which open banking exists to replace, and it trains customers to type bank passwords into pages that aren't their bank's.

Outcome

Payment completion went from 64% to 82%, mostly at the bank step and the return.

@itsnas consent-funnel.svg
Pay by bank completion, step by step, before and afterOf 100 customers who chose pay by bank, 91 picked a bank, 87 accepted the consent screen, 84 reached their bank, 68 authorised and 64 returned to the merchant. After the changes, the same steps read 96, 93, 91, 83 and 82. The biggest drop, before and after, is between reaching the bank and authorising.91%87%84%68%64%96%93%91%83%82%BeforeAfter0%25%50%75%100%Bank pickedConsentedAt bankAuthorisedReturnedStill in the journey
Share of customers still in the journey at each step.

On data access, about a third of connections used to lapse at each 90-day mark; with one in-app prompt, under one in ten did. Merchants noticed it first as fewer support tickets about "pay by bank not working", most of which had been customers lost on the way back.

Solving something similar?

I take on select engineering work like this.

Work with me

What I'd do differently

Break the funnel down per bank from the first week. For months we read one blended completion rate, which hid that a handful of banks without app-to-app support were dragging it down; the per-bank view turned "improve conversion" into a short list of banks to chase.