KYCIS SDK Docs
Advanced Usage

Manual Integration

Integration without heavy SDK automation assumptions

Manual Mode Principles

When you need explicit control over SDK behavior:

  • Call SDK APIs at known UX milestones
  • Control when to emit context-heavy events
  • Keep data contracts strict and deterministic
  • Verify behavior via backend activity

When to Use Manual Mode

  • Complex navigation not suitable for auto-tracking
  • Need explicit control over event timing
  • Testing or debugging scenarios
  • Custom lifecycle requirements

Minimal Manual Integration

// 1. Initialize (still required)
AI.init(
  application = this,
  apiKey = "your-api-key",
  userId = "user-123",
  policy = RuntimePolicy(
    backendBaseUrl = "https://kycis.zynnex.in/v1",
    triggerStartMode = TriggerStartMode.CONFIRM_UI,
    passiveEvalEnabled = false  // Disable passive evaluation
  )
)

// 2. Skip attach() — no lifecycle tracking

// 3. Manual user set
AI.setUser(id = "user-123", phone = "9876543210", phoneMasked = true)

Explicit Event Emission

Control exactly when events fire:

// Screen entry (manually controlled)
fun onScreenEnter(screenId: String) {
  AI.setKycStep(screenId)
  AI.reportScreenState(
    screen = screenId,
    metadata = mapOf("manual" to "true")
  )
}

// Input tracking (throttled manually)
fun onInputChanged(componentId: String, value: String) {
  // Your own debounce logic
  debouncer.debounce("$componentId-input", 500) {
    AI.reportComponentInput(
      componentId = componentId,
      hint = maskValue(value),
      masked = true
    )
  }
}

// Validation (explicit call)
fun onValidationFailed(componentId: String, rule: String) {
  AI.trackValidationFailure(
    failureReasonCode = rule,
    componentId = componentId
  )
}

Manual Trigger Evaluation

Skip automatic triggers, evaluate manually:

// Disable auto triggers
RuntimePolicy(
  triggerSettings = TriggerSettings(
    autoTriggerEnabled = false
  )
)

// Manually evaluate when needed
fun checkShouldOfferHelp() {
  // Your own logic
  if (errorCount > 2 || timeOnScreen > 30) {
    // Show your own UI
    showHelpOffer()
  }
}

// Direct assistant start
fun onUserAcceptsHelp() {
  AI.startAssistant()
}

Custom Lifecycle

When AI.attach() doesn't fit:

// Your own activity tracking
class MyLifecycleCallbacks : Application.ActivityLifecycleCallbacks {
  override fun onActivityResumed(activity: Activity) {
    // Custom screen detection
    val screenId = detectScreen(activity)
    AI.setKycStep(screenId)
  }
}

// Register manually
application.registerActivityLifecycleCallbacks(MyLifecycleCallbacks())

Verification Without Auto-Tracking

Since reduced tracking mode applies:

// Add your own analytics
AI.setStatusListener { status ->
  analytics.track("kycis_manual", mapOf(
    "code" to status.code.name
  ))
}

// Verify in backend
// Check /api/activity for all expected events

Trade-offs

AspectAuto (attach)Manual
SetupOne lineExplicit everywhere
Screen trackingAutomaticManual calls
Passive signalsAvailableLimited
ControlSDK decidesYou decide
Debug complexityLowerHigher

Keep some automation, add manual where needed:

// Enable attach for basic tracking
AI.attach(this)

// But override specific behaviors
RuntimePolicy(
  passiveEvalEnabled = true,  // Keep passive
  triggerSettings = TriggerSettings(
    autoTriggerEnabled = false  // But control triggers
  )
)

// Manual trigger with custom UI
fun onCustomStruggleDetected() {
  showCustomHelpDialog()
}

On this page