kyc.tm_kyc_apply.flow_type (UAE_KYC_FULL / UAEPASS / SIGNZY_FULL). Live 7d completion: UAE_KYC_FULL 65.5%, UAEPASS 54.9%, SIGNZY_FULL 46.3%. Daily Bad-KYC ~40% (spikes 45.5% on 06-06 & 06-14, aligned with UAEPASS incidents). UAE Pass root cause: 94% of failures = job check timeout (document-verification timeout, via outman.t_uaepass_monitor_event), only 6% user-reject. Interactive 3-tab dashboard updated with real data. Remaining open question: uid ↔ member_id join key for client-attribute filters (country / version / mp-version / platform).
KYC gates every Botim Pay finance feature (transfers, prepaid card, top-up). When KYC goes bad, downstream revenue is blocked. Today we have server-side success on submitted applications (~50% completion, dedup) — but were blind to the top-of-funnel drop where ~40% never even start a verification method. This doc joins the front-end funnel with server-side completion to see the whole picture, and drives three things:
KYC Flow Entered, KYC Verification Started, …) live inside kMPH5 with all business properties — including Entry Point (intent source). Business properties appear either at the JSON root or under mp_detail_obj (dual schema); regexp_extract reads across both. Completion & errors are reconciled with server-side KYC tables.A Bad KYC is an attempt that showed genuine intent but failed to reach a successful server-side completion — excluding pure user cancellation. A session is Bad KYC when all hold:
KYC Verification Started (intent shown), ANDCompleted, ANDExcluded (not Bad KYC): user Cancel, "just exploring", never-started, "no Emirates ID right now" (will-retry).
Metric: Bad KYC rate = Bad KYC sessions / sessions reaching Verification Started, sliced by channel × client dims. (Session-level once session_id lands; user-level until then.)
Every KYC order falls in exactly one bucket — A + B + C + D = 100%:
| Bucket | Meaning | Formula (of all orders) | Observed | Source |
|---|---|---|---|---|
| A · No-intent | entered, never started verification | (Entered − Started) / Entered | ~40% | front-end |
| B · Bad KYC | intent but KYC failed (pre-audit) | (Started − KYC_passed − Cancel) / Entered | ~25% | tm_kyc_apply |
| C · Risk/audit reject | KYC passed but audit rejected | Audit_reject / Entered | ~0.4% | tm_audit_task (R) |
| D · Final success | KYC passed + audit passed | (KYC_passed − Audit_reject) / Entered | ~35% | tm_kyc_apply |
Variables: Entered = Flow Entered distinct uid (denominator) · Started = Verification Started · KYC_passed = journey_flag=1 OR step IN ('DOWN','PRE_EID_EXPIRY') · Cancel = user-reject / give-up / not-comfortable (excluded from Bad KYC) · Audit_reject = tm_audit_task status=R.
Audit funnel (30d): entered 2,016 → reject 1,120 (55.6%) / pass 886 (44%); 97% triggered by CHANNEL_HINT_REVIEW. Top reject reasons: Portrait Inspection Failed 66%, Document & ICP mismatch — expiry 17% / DOB 9%.
Insight: the two biggest losses are No-intent (~40%) and Bad KYC (~25%); manual audit (C) is a tiny slice (~2k/month). Bad KYC is dominated by UAE Pass job check timeout + UAE KYC "EID not scanned".
logs_footprint_mp (raw JSON) + kyc.* server tables
│ flatten / parse
▼
① vew.kyc_event_flatten_di DWD flatten table (one row per event)
│ GROUP BY
▼
② ads_kyc_channel_funnel_di per-channel success funnel
③ ads_kyc_failure_reason_di failure reasons
④ ads_kyc_leave_reason_di drop-off reasons
+
⑤ dim_kyc_entry_point entry-point code → business name (optional)
+
⑥ dwd_kyc_apply_di server apply mirror (TiDB tm_kyc_apply) — required for Bad KYC
| # | Table | Layer | Status |
|---|---|---|---|
| ① | vew.kyc_event_flatten_di | DWD flatten | Built (rerun for new schema) |
| ② | vew.ads_kyc_channel_funnel_di | ADS result | To build |
| ③ | vew.ads_kyc_failure_reason_di | ADS result | To build |
| ④ | vew.ads_kyc_leave_reason_di | ADS result | To build |
| ⑤ | vew.dim_kyc_entry_point | DIM | Optional · needs dict |
| ⑥ | vew.dwd_kyc_apply_di | DWD (server) | To build · required for Bad KYC |
Can we compute Bad KYC today? Bad KYC needs server completion (is_passed) which the front-end flatten table doesn't have — so it comes from ⑥ dwd_kyc_apply_di (mirror of TiDB tm_kyc_apply). Server-only Bad KYC (per channel/day) = started − kyc_passed − cancel, computable once ⑥ is built. The full decomposition (incl. No-intent + client-attr filters) additionally needs the uid ↔ member_id join key (P0).
Each channel has a different flow / pages, so funnels must be built per channel — the same event cannot be compared across channels.
| Channel | Form | Key trait |
|---|---|---|
| UAE Pass | Jumps out of app for authorization (black box to front-end) | Handoff invisible to us — rely on server-side error callback |
| UAE KYC | In-app flow | Has its own pages: EID Details Viewed / Confirmed |
| signzy | TBD | Milestone events to be confirmed by eng |
ads_kyc_channel_funnel_di (tall)Grain: dt × channel × combination dims × funnel_step. Metric: users (distinct uid; distinct session once available).
| step | All | UAE KYC | UAE Pass |
|---|---|---|---|
| 0 | Flow Entered (channel=ALL) | — | — |
| 1 | Verification Started | Verification Started | Verification Started |
| 2 | — | EID Details Viewed | UAE Pass Continue |
| 3 | — | EID Confirmed | SDK Return (needs tracking) |
| 4 | — | Submitted (server) | Submitted (server) |
| 5 | — | Completed (server) | Completed (server) |
ads_kyc_failure_reason_diGrain: dt × channel × failure_source × failure_reason × dims. Sources: frontend_error (Error Type), server_callback (error code), audit_reject (tm_audit_log.memo), status_page (Page Code). Must split user cancel (Cancel) vs system error.
ads_kyc_leave_reason_diGrain: dt × channel × leave_source × leave_page × leave_reason × dims. Primary signal is Exit Bottom sheet Viewed — not the Leave-click event (most users just close the app).
Full DDL in analysis/schema-ddl.sql. ②③④ sample figures are illustrative (06-01 distribution); error_code / server values pending eng.
vew.kyc_event_flatten_di — DWD flatten (partition dt · PARQUET)Business fields: uid, event, entry_point, verification_type, kyc_flow_type, kyc_vendor, error_type, page_code, kyc_status, reason, page_dropped_from, cta_clicked, industry, renewal_flow, uri_path
Client dims: client_version, mp_version, os_version, device_brand, device_model, device_type, net_type, language, region, uid_region, ip_region, ip_isp, event_ts + partition dt (all STRING; event_ts BIGINT)
| uid | event | entry_point | verification_type | kyc_flow_type | kyc_vendor | error_type | region | client_ver | dt |
|---|---|---|---|---|---|---|---|---|---|
| f7bb… | KYC Flow Entered | wallet | New User KYC | AE | 4.9.1 | 20260601 | |||
| f7bb… | KYC Verification Started | wallet | Verify with UAE Pass | New User KYC | UAE pass | AE | 4.9.1 | 20260601 | |
| 192c… | KYC UAE Pass Validation Error | Verify with UAE Pass | New User KYC | Cancel | AE | 4.9.1 | 20260601 | ||
| e0b0… | KYC Emirates ID details Confirmed | TO_REMITTENCE | Scan or upload your Emirates ID | New User KYC | UAE KYC SDK | AE | 4.7.2 | 20260601 |
vew.ads_kyc_channel_funnel_di — per-channel funnel (tall · partition dt)Fields: channel, entry_point, kyc_flow_type, verification_type, client_version, mp_version, os_platform, region, net_type, step_order INT, step_name, users BIGINT, events BIGINT, dt
| channel | entry_point | flow | region | step_order | step_name | users | dt |
|---|---|---|---|---|---|---|---|
| ALL | wallet | New | AE | 0 | Flow Entered | 4,820 | 20260601 |
| UAE_KYC | wallet | New | AE | 1 | Verification Started | 1,820 | 20260601 |
| UAE_KYC | wallet | New | AE | 3 | EID Confirmed | 968 | 20260601 |
| UAE_KYC | wallet | New | AE | 5 | Completed (server) | 512 | 20260601 |
| UAE_Pass | TO_REMITTENCE | New | AE | 1 | Verification Started | 1,340 | 20260601 |
| UAE_Pass | TO_REMITTENCE | New | AE | 5 | Completed (server) | 198 | 20260601 |
vew.ads_kyc_failure_reason_di — failure reasons (partition dt)Fields: channel, failure_source, failure_reason, error_code, is_user_cancel BOOLEAN, entry_point, kyc_flow_type, verification_type, client_version, mp_version, region, users BIGINT, events BIGINT, dt
| channel | failure_source | failure_reason | error_code | is_user_cancel | users | dt |
|---|---|---|---|---|---|---|
| UAE_Pass | frontend_error | Cancel | true | 1,208 | 20260601 | |
| UAE_Pass | server_callback | UAEPASS_TIMEOUT | E_UP_408 | false | 340 | 20260601 |
| UAE_KYC | status_page | renewNotMatch | false | 286 | 20260601 | |
| UAE_KYC | audit_reject | Upload clear EID (both sides) | false | 187 | 20260601 |
vew.ads_kyc_leave_reason_di — drop-off reasons (partition dt)Fields: channel, leave_source, leave_page, leave_reason, entry_point, kyc_flow_type, client_version, mp_version, region, users BIGINT, dt
| channel | leave_source | leave_page | leave_reason | users | dt |
|---|---|---|---|---|---|
| ALL | exit_sheet | /kyc/home | exit_sheet_viewed | 6,486 | 20260601 |
| UAE_Pass | mp_close | SDK auth page (needs tracking) | (unknown) | 580 | 20260601 |
| UAE_KYC | leave_click | /kyc/document-review | I'll do it later | 312 | 20260601 |
vew.dim_kyc_entry_point — entry-point dictionary (no partition · optional)Fields: entry_point_code, entry_point_name, category, is_tech_source BOOLEAN, note
| code | name | category | is_tech_source | note |
|---|---|---|---|---|
| wallet | Wallet activation | wallet | false | |
| TO_REMITTENCE | International transfer | transfer | false | misspelled Remittance |
| mp-ogold / mpogold | oGold | other | false | merge two spellings |
| uniapp | (tech container) | tech | true | exclude from analysis |
Completed does not fire on redirect flows.| Priority | Item | Why |
|---|---|---|
| P1 | Fix double-firing on 8 impression/click events (Exit Bottom sheet 28% highest) | Event counts inflated 10–28% |
| P1 | Switch completion + errors to server-side source | Front-end Completed not fired on redirect; UAE Pass handoff is a black box |
| P2 | Server-issued session_id carried in every front-end event; refine analysis from user-level to session-level | Removes multi-attempt noise; makes per-attempt funnels correct |
| P2 | Add specific page name to leave events (own page vs SDK page) | Locate where UAE Pass users vanish in the SDK black box |
| P3 | UAE KYC confirm page: record retry/leave click count + problem encountered | Diagnose in-app verification friction |
| P3 | Backfill Entry Point (~30% empty) + standardize codes | Intent attribution coverage |
kyc_vendor + verification_type → 3 channels.tm_kyc_apply carry channel / entry_point?).session_id linkage to member_id / apply on the server.mp-ogold/mpogold, MANDATORY_KYC/_V2).tr_leave_record excludes it.)