Back to all posts

How I Reduced Login Failures by 60% — A Deep Dive Into Auth UX

The Problem

PhonePe's login screen had a 15% failure rate. That means roughly 1 in 7 users couldn't log in on their first attempt. At 500M+ users, that's tens of millions of frustrated people.

I was tasked with fixing it. Here's the complete journey.

Understanding the Failures

First, I instrumented every possible failure point:

  • OTP never received (38% of failures) — Network issues, SMS gateway delays, or incorrect phone numbers
  • OTP expired (24% of failures) — Users took too long to enter the code
  • Wrong OTP entered (19% of failures) — Typos, confusion with other OTPs
  • App crash during login (11% of failures) — Edge cases in the auth flow
  • Network timeout (8% of failures) — Slow or unstable connections

The Solutions

Fix 1: Auto-read OTP with SMS Retriever API

The biggest win. Instead of asking users to manually type a 6-digit OTP, we implemented the SMS Retriever API to auto-read and auto-fill.

val client = SmsRetriever.getClient(context)

val task = client.startSmsRetriever()

task.addOnSuccessListener {

// Register broadcast receiver for incoming SMS

registerReceiver(smsReceiver, intentFilter)

}

Impact: OTP-related failures dropped by 45%.

Fix 2: Graceful Retry with Exponential Backoff

Instead of showing a generic "Something went wrong" error, we implemented smart retry:

  • First failure: Auto-retry silently after 2 seconds
  • Second failure: Show "Retrying..." with a spinner
  • Third failure: Offer alternatives (call-based OTP, WhatsApp OTP)

Impact: Network timeout failures dropped by 60%.

Fix 3: OTP Timer Extension

Our OTP expired after 30 seconds. User research showed that 35% of users on low-end devices needed more than 30 seconds (app switching to SMS app and back was slow). We extended to 60 seconds and added a visible countdown.

Impact: OTP expiry failures dropped by 50%.

Fix 4: Phone Number Validation

We added real-time validation as the user types:

  • Format check (10 digits, valid prefix)
  • Carrier detection (show carrier name for confirmation)
  • Previously used numbers (auto-suggest from account history)

Impact: Wrong number submissions dropped by 70%.

Fix 5: Crash-Free Login Flow

We found 8 edge cases causing crashes:

  • Config change during OTP verification
  • Back press during API call
  • Dual SIM number picker dismissal
  • Low memory during biometric prompt

Each was fixed with proper lifecycle handling and state restoration.

Impact: Auth-related crashes went to zero.

The Design Changes

Beyond technical fixes, we redesigned the UX:

  • Single-screen flow — Previously, phone number and OTP were on separate screens. We combined them with a smooth transition. Fewer navigation steps = fewer drop-offs.
  • Trust signals — Added PhonePe's security badge, "256-bit encrypted" text, and RBI compliance notice. Users are entering sensitive info — they need reassurance.
  • Error messages that help — Changed "Invalid OTP" to "That code didn't match. Check your SMS and try again." Changed "Network error" to "Slow connection. We'll keep trying."
  • Loading states — Replaced blank screens during API calls with skeleton loaders and progress indicators. Users who see progress are 3x more patient.

The Results

After 6 weeks of incremental rollout:

  • Login failure rate: 15% → 6% (60% reduction)
  • Average login time: 28 seconds → 12 seconds
  • Support tickets for login issues: -73%
  • User satisfaction (login NPS): +22 points

Key Lessons

  • Instrument everything — You can't fix what you can't measure. Every failure mode needs a distinct analytics event.
  • Don't blame the user — "Wrong OTP" is a UX failure, not a user failure. Make it harder to fail.
  • Test on real conditions — Our lab testing missed issues that only appeared on 2G networks with 512MB RAM devices.
  • Small changes, big impact — The OTP timer change was a one-line code change that eliminated 12% of all login failures.

Login is your app's front door. Make it effortless.