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
| Aspect | With Navigation | Without Navigation |
|---|---|---|
| Schemas | Registered before init | None |
| attach() | Yes | No |
| setKycStep | On every screen | Once on activity |
| Passive triggers | Enabled | Disabled |
| Screen context | Automatic | Manual |
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
-
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}$" ) ) -
Explicit validation metadata
AI.trackValidationFailure( failureReasonCode = "phone_invalid", componentId = "phone_field", hint = "invalid_value", masked = false, expectedPattern = "10-digit Indian mobile", businessStep = "CONTACT_INFO" ) -
Manual trigger logic
var errorCount = 0 fun onValidationFailed() { errorCount++ if (errorCount >= 2) { showHelpSuggestion() } }
Verification
Check /api/activity:
identityevent presentcomponent_inputevents havescreenfieldvalidation_failedincludes metadata- Manual
session_startwhen help clicked