Skip to content
Tolinku
Tolinku
Sign In Start Free
Use Cases · · 5 min read

KYC Flow Deep Links: Streamlining Identity Verification

By Tolinku Staff
|
Tolinku fintech deep linking dashboard screenshot for use cases blog posts

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

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:

  1. Open the app if installed (Universal Link / App Link).
  2. Open the mobile web KYC flow if the app is not installed.
  3. 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 Email /verify/{last-step} "You're X steps away from activation"
3 days Push /verify "Your account is waiting"
7 days Email /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

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
}

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.

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.

Ready to add deep linking to your app?

Set up Universal Links, App Links, deferred deep linking, and analytics in minutes. Free to start.