KYC (Know Your Customer) verification is where fintech apps lose the most users. The multi-step process (personal information, document upload, selfie verification, address proof) is tedious, and users frequently abandon midway. Deep links can recover these users by sending them back to exactly where they left off.
This guide covers how to use deep links to improve KYC completion rates. For banking app onboarding, see banking app onboarding deep links. For general onboarding deep links, see user onboarding deep links.
The KYC Abandonment Problem
Typical KYC completion rates for fintech apps:
| Step | Completion Rate | Drop-off |
|---|---|---|
| Start KYC | 100% | – |
| Personal information | 85% | 15% |
| Document upload (ID) | 65% | 20% |
| Selfie verification | 55% | 10% |
| Address verification | 48% | 7% |
| Review and submit | 45% | 3% |
More than half of users who start KYC do not complete it. Each user who abandons represents a lost customer that you paid to acquire.
Route Patterns
/verify → KYC landing page (resume from last step)
/verify/personal-info → Personal information form
/verify/document → Document upload step
/verify/document/{type} → Specific document type (passport, license, id-card)
/verify/selfie → Selfie/liveness check
/verify/address → Address verification
/verify/review → Review and submit
/verify/status → Verification status
/verify/retry/{step} → Retry a failed step
Recovery Deep Links
Abandonment Email
When a user starts KYC but does not complete it within 24 hours:
<p>You're almost done setting up your account. Just a few more steps to complete verification.</p>
<p>You left off at: <strong>Document Upload</strong></p>
<a href="https://links.finapp.com/verify/document">
Continue Verification
</a>
The deep link takes the user directly to the step they abandoned, not back to the beginning. This is critical. Forcing users to re-enter information they already submitted is the fastest way to lose them.
Push Notification Recovery
{
"title": "Complete your verification",
"body": "Upload your ID to finish account setup. It takes less than 2 minutes.",
"deep_link": "https://links.finapp.com/verify/document",
"category": "kyc_reminder"
}
SMS Recovery
For users who abandoned on mobile web and may not have the app:
Complete your verification to activate your account: links.finapp.com/verify
This link should:
- Open the app if installed (Universal Link / App Link).
- Open the mobile web KYC flow if the app is not installed.
- Preserve the user's session so they resume where they left off.
Implementation
Tracking KYC Progress
Store the user's KYC progress server-side so deep links can resume correctly:
func handleVerifyDeepLink(_ url: URL) {
guard authManager.isAuthenticated else {
pendingDeepLink = url
showLogin()
return
}
let segments = url.pathComponents
// If no specific step, resume from last incomplete step
if segments.count <= 2 || segments.last == "verify" {
resumeKYC()
return
}
let requestedStep = segments[2]
// Verify the user can access this step
let kycState = kycManager.getCurrentState()
switch requestedStep {
case "personal-info":
showPersonalInfoForm(prefilled: kycState.personalInfo)
case "document":
if kycState.personalInfoComplete {
let docType = segments.count >= 4 ? segments[3] : nil
showDocumentUpload(preferredType: docType)
} else {
// Can't skip ahead
showPersonalInfoForm(prefilled: kycState.personalInfo)
}
case "selfie":
if kycState.documentUploaded {
showSelfieVerification()
} else {
resumeKYC() // Go to the next incomplete step
}
case "status":
showVerificationStatus()
case "retry":
let failedStep = segments.count >= 4 ? segments[3] : nil
handleRetry(step: failedStep)
default:
resumeKYC()
}
}
func resumeKYC() {
let state = kycManager.getCurrentState()
let nextStep = state.nextIncompleteStep
switch nextStep {
case .personalInfo: showPersonalInfoForm(prefilled: state.personalInfo)
case .document: showDocumentUpload(preferredType: nil)
case .selfie: showSelfieVerification()
case .address: showAddressVerification()
case .review: showReviewAndSubmit()
case .complete: showVerificationStatus()
}
}
Handling Failed Verification
When a KYC step fails (blurry document, face mismatch), send a deep link to retry:
{
"title": "Document verification failed",
"body": "Your ID photo was unclear. Please retake the photo.",
"deep_link": "https://links.finapp.com/verify/retry/document",
"category": "kyc_retry"
}
<p>We couldn't verify your identity document. Common issues:</p>
<ul>
<li>Photo was blurry or too dark</li>
<li>Document was partially cut off</li>
<li>Glare obscured the text</li>
</ul>
<a href="https://links.finapp.com/verify/retry/document">
Retake Document Photo
</a>
KYC Recovery Campaign
A structured recovery campaign with deep links:
| Timing | Channel | Deep Link | Message |
|---|---|---|---|
| 1 hour after abandonment | Push | /verify |
"Continue setting up your account" |
| 24 hours | /verify/{last-step} |
"You're X steps away from activation" | |
| 3 days | Push | /verify |
"Your account is waiting" |
| 7 days | /verify |
"Complete verification to access all features" | |
| 14 days | SMS | /verify |
Final reminder with direct link |
Each message deep links to the user's specific abandonment point, not a generic page.
Security
Preventing Deep Link Abuse
KYC deep links should not expose the verification flow to abuse:
func validateKYCDeepLink(_ url: URL) -> Bool {
// 1. User must be authenticated
guard authManager.isAuthenticated else { return false }
// 2. User must have an active KYC session
guard kycManager.hasActiveSession else { return false }
// 3. Rate limit retries
if url.path.contains("retry") {
guard kycManager.retryCount < 5 else {
showError("Too many retry attempts. Please contact support.")
return false
}
}
return true
}
Data in Deep Links
Never include personal data in KYC deep links:
BAD: /verify/document?name=John+Doe&dob=1990-01-15
GOOD: /verify/document
The app retrieves the user's KYC state from the server after authentication. The deep link only specifies which step to show.
Measuring KYC Deep Link Impact
| Metric | Without Deep Links | With Deep Links |
|---|---|---|
| KYC completion rate | 45% | 60-70% |
| Time to complete KYC | 3-5 days average | 1-2 days average |
| Support tickets (KYC-related) | High | Reduced |
| User acquisition cost (effective) | Higher (many acquired users never complete KYC) | Lower |
The improvement comes from reducing abandonment at each step. Users who are deep linked directly to their abandonment point are 3-4x more likely to complete that step than users who receive a generic "complete your verification" email.
Tolinku for KYC Flows
Tolinku supports the route patterns KYC flows need. Define verification step routes in the Tolinku dashboard. Deferred deep linking ensures that users who install the app from a KYC recovery link land on the correct verification step.
For banking onboarding, see banking app onboarding deep links. For fintech deep linking, see deep linking for fintech and banking apps.
Get deep linking tips in your inbox
One email per week. No spam.