KYCIS SDK Docs
Examples

Example - Without Navigation Tracking

Minimal integration when navigation isn't instrumented

Scenario

Single-screen or simple apps without complex navigation:

  • One-page KYC form
  • No navigation framework
  • Manual context control

Trade-offs

Lower quality contextual assistance:

  • No automatic screen detection
  • Limited trigger signals
  • Manual assistant start only

Compensate with:

  • Richer component input metadata
  • Explicit screen hints
  • Stronger host-side control

Implementation

1. Minimal Application Setup

class SimpleKycApplication : Application() {
  override fun onCreate() {
    super.onCreate()
    
    // Initialize without schemas
    AI.init(
      application = this,
      apiKey = "your-api-key",
      userId = "runtime-user-id",
      policy = RuntimePolicy(
        backendBaseUrl = "https://kycis.zynnex.in/v1",
        triggerSettings = TriggerSettings(
          autoTriggerEnabled = false  // Disable auto triggers
        )
      )
    )
    
    // Skip attach() — no lifecycle tracking needed
  }
}

2. Single Screen Activity

class KycFormActivity : AppCompatActivity() {
  
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    // Set user once
    AI.setUser(
      id = "user-123",
      phone = "9876543210",
      phoneMasked = true
    )
    
    // Set screen context once
    AI.setKycStep("kyc_form")
    
    setContentView(R.layout.activity_kyc_form)
    
    setupForm()
    setupHelpButton()
  }
  
  private fun setupForm() {
    val phoneInput = findViewById<EditText>(R.id.phone_input)
    val panInput = findViewById<EditText>(R.id.pan_input)
    
    // Track input with debounce
    phoneInput.addTextChangedListener(object : TextWatcher {
      private var debounceJob: Job? = null
      
      override fun afterTextChanged(s: Editable?) {
        debounceJob?.cancel()
        debounceJob = lifecycleScope.launch {
          delay(500)
          AI.reportComponentInput(
            componentId = "phone_field",
            hint = maskPhone(s.toString()),
            masked = true,
            screen = "kyc_form"
          )
        }
      }
      
      override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
      override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
    })
    
    // Similar for PAN
    panInput.addTextChangedListener(/* ... */)
  }
  
  private fun setupHelpButton() {
    val helpButton = findViewById<Button>(R.id.help_button)
    
    AI.setVoiceSessionListener { result ->
      if (result.isValid) {
        startVoiceCall(result)
      } else {
        Toast.makeText(this, "Voice not available", Toast.LENGTH_SHORT).show()
      }
    }
    
    helpButton.setOnClickListener {
      AI.startAssistant()
    }
  }
  
  private fun startVoiceCall(result: VoiceSessionResult) {
    // Connect to LiveKit
    // Show call UI
  }
  
  fun onSubmit() {
    val phone = findViewById<EditText>(R.id.phone_input).text.toString()
    val pan = findViewById<EditText>(R.id.pan_input).text.toString()
    
    var hasError = false
    
    if (!isValidPhone(phone)) {
      AI.trackValidationFailure(
        failureReasonCode = "phone_invalid",
        componentId = "phone_field",
        screen = "kyc_form",
        hint = maskPhone(phone),
        masked = true
      )
      hasError = true
    }
    
    if (!isValidPan(pan)) {
      AI.trackValidationFailure(
        failureReasonCode = "pan_invalid",
        componentId = "pan_field",
        screen = "kyc_form",
        hint = maskPan(pan),
        masked = true
      )
      hasError = true
    }
    
    if (hasError) {
      // Show errors
      return
    }
    
    // Submit form
  }
}

Key Differences from Navigation Example

AspectWith NavigationWithout Navigation
SchemasRegistered before initNone
attach()YesNo
setKycStepOn every screenOnce on activity
Passive triggersEnabledDisabled
Screen contextAutomaticManual

When This Pattern Works

Appropriate for:

  • Single-page forms
  • Simple onboarding
  • Prototypes and demos
  • Apps with custom navigation not suitable for auto-tracking

Limitations

  • No automatic trigger detection
  • Limited context for voice agent
  • Manual help button only
  • No time/idle-based triggers

Compensating Strategies

  1. Rich component input

    AI.reportComponentInput(
      componentId = "phone_field",
      hint = "98****7654",
      masked = true,
      screen = "kyc_form",
      componentType = "text_input",
      properties = mapOf(
        "field_label" to "Phone Number",
        "validation_pattern" to "^[6-9]\\d{9}$"
      )
    )
  2. Explicit validation metadata

    AI.trackValidationFailure(
      failureReasonCode = "phone_invalid",
      componentId = "phone_field",
      hint = "invalid_value",
      masked = false,
      expectedPattern = "10-digit Indian mobile",
      businessStep = "CONTACT_INFO"
    )
  3. Manual trigger logic

    var errorCount = 0
    
    fun onValidationFailed() {
      errorCount++
      if (errorCount >= 2) {
        showHelpSuggestion()
      }
    }

Verification

Check /api/activity:

  • identity event present
  • component_input events have screen field
  • validation_failed includes metadata
  • Manual session_start when help clicked

On this page