🔦 Lighthouse

Bad OTP Dashboard

dt = 2026-06-28 · single-day
Bad OTP / Cost
User Behavior
↩ Briefings 📖 Data & lineage
Filter: all

Fail composition</> SQLserver

of total sends — failure is user-side

        
💡 INSIGHTNO_VERIFY dominates, not wrong code. Carrier ~100% — fixing drop-off beats switching vendor.

Wasted spend by reason</> SQLserver

$ on sends that never verified

        

Verify fail rate by vendor</> SQLserver

carrier ~100% on all — gap is completion

        
💡 INSIGHT~13 pt spread at equal delivery. Route high-NO_VERIFY traffic off the worst vendor.

Fail rate by country</> SQLserver

top corridors · Unknown (=NO_VERIFY) excluded

        

🎯 Action levers

P0
Reduce NO_VERIFY drop-off — App/UX + auto-fill, not a vendor switch. Biggest waste.
P0
Route high-NO_VERIFY traffic off the worst vendor toward Etisalat-class delivery.
P1
Trend + anomaly panel needs multi-day — wire to 122-day server history.

① Funnel — send → enter → verify</> SQLclient

trace-deduped · 61.8% verify · 44.6% never enter

      
💡 INSIGHTBiggest leak: "saw page, never typed" (31,478) — input friction, not delivery.

② Verification failure reasons</> SQLclient

n = 14,881 failed traces

        
💡 INSIGHT87% = wrong code. Help users mis-type less (auto-fill + clearer UI).

③ Rate-limit blocks</> SQLclient

89,508 events = 36.4% of requests

        
💡 INSIGHT1 in 3 blocked. Number Limit + Others dominate; thresholds look strict.

④ Send → verified total time</> SQLclient

distribution ·

      
💡 INSIGHT68% within 30s, 91% within 60s; tail ~9% over a minute.

⑤ Top-50 countries — input vs verify/retry</> SQLclient

median seconds, sorted by total

      
💡 INSIGHTTwo slows: Qatar verify/retry 34s; Iran input 38s.

⑥ Auto-fill coverage — platform × version</> SQLclient

auto-fill is iOS-only · live-filtered by Platform + Version

        
💡 INSIGHTAndroid = 0% (105k entries) — big lever. iOS 31.6%→35.8%.

⑦ Auto-fill vs manual — speed</> SQLclient

send → filled/verified, seconds

        
💡 INSIGHT0.7s vs 23s median — saves ~22s. iOS-only.

⑧ Timestamp semantics — platform × version</> SQLclient

same field, different meaning per platform — a tracking gap

      
PlatformVersiontotalrelativeepochnull
iOS4.12.016,4280%99%1%
iOS4.11.18,0880%85%15%
Android4.11.3104,91395%0%5%
Android4.11.118682%0%18%
both≤4.100%0%100%
💡 INSIGHTiOS=epoch, Android=relative — not a version flip (rollout skew). Fix: split into input_duration_ms + event_ts.

⑨ Root causes & tracking gaps

  • 🔑 Auto-fill only 4% overall, 0% on Android — highest-leverage fix.
  • Gap 1 — Block has no identity (no trace_id/uid) → count only.
  • Gap 3 — auto-fill orphaned: Entered uses a fresh trace_id → conversion unmeasurable until it reuses the session trace_id.
  • Gap 4 — timestamp semantics differ by platform; split the field.

🎯 Action items

P0
Add Android auto-fill (SMS Retriever + User Consent) — 0% today, saves ~22s/verify.
P0
Fix Gap 3 — reuse session trace_id on auto-fill Entered.
P1
Investigate Qatar delivery & slow corridors (Iran).
P1
Evaluate loosening rate-limit thresholds — 1 in 3 blocked.

📅 Date range ·Tab1

backend: checking…

🌍 Country ·Tab1

📡 Send channel ·Tab1

📱 Platform ·Tab2

🏷 Version ·Tab2

⚙ More

Cross-source note: Country/Channel exist only server-side, Platform/Version only client-side (no join key) — each filters its own tab. Multi-day + full client filtering come with the Grafana-backed build.