Event System
Sending Events
When and how to emit each event type
Event Order
Recommended emission sequence:
identity— when user/session is knownscreen_schema— when entering a screen (with registered schema)component_input— on meaningful input changesvalidation_failed— on actionable validation failures
Identity Event
Set when user is identified:
AI.setUser(
id = "user-123",
phone = "9876543210",
phoneMasked = true
)Backend event: identity
Key fields:
{
"event": "identity",
"properties": {
"user_id": "user-123",
"phone": "9876543210",
"phone_masked": true
}
}Note: Android SDK sends session_id: "unknown" until real session exists.
Screen Schema Events
Full Schema (registered)
Register schemas before init or on navigation:
// Before init for startup push
AI.registerScreenSchema(
ScreenSchema(
screenId = "pan_entry",
title = "Enter PAN Details",
components = listOf(
ComponentSpec(
id = "pan_field",
type = "text_input",
label = "PAN Number",
validationRules = listOf(
ValidationRule(
ruleId = "pan_format",
pattern = "[A-Z]{5}[0-9]{4}[A-Z]",
errorMessage = "Invalid PAN format"
)
)
)
)
)
)Backend event: screen_schema
Lazy Schema Beacon (no registration)
When no schema registered for step:
AI.setKycStep("unknown_screen")Backend event: screen_schema_lazy (minimal, no schema body)
Component Input Events
Report redacted input hints:
AI.reportComponentInput(
componentId = "pan_field",
hint = "ABCDE****F", // Masked/redacted
masked = true,
screen = "pan_entry",
componentType = "text_input"
)Backend event: component_input
Key fields:
{
"event": "component_input",
"component_id": "pan_field",
"masked": true,
"properties": {
"hint": "ABCDE****F"
}
}Important:
- Always mask PII (phone, PAN, Aadhaar)
- Debounce 300-500ms for text input
- Only send meaningful changes
Validation Failure Events
Track field-level validation:
// Minimal
AI.trackValidationFailure(
failureReasonCode = "pan_invalid",
componentId = "pan_field"
)
// Recommended (explicit metadata)
AI.trackValidationFailure(
failureReasonCode = "pan_invalid",
componentId = "pan_field",
componentType = "text_input",
expectedPattern = "[A-Z]{5}[0-9]{4}[A-Z]",
validationRuleId = "pan_format_v1",
hint = "ABCDE****F",
masked = true,
businessStep = "PAN_ENTRY",
validationIntent = "PAN_FORMAT",
recoveryPlaybookId = "retry_pan_01"
)Backend event: validation_failed
Key fields:
{
"event": "validation_failed",
"errors": ["pan_invalid"],
"failure_reason_code": "pan_invalid",
"component_id": "pan_field",
"component_type": "text_input",
"expected_pattern": "[A-Z]{5}[0-9]{4}[A-Z]",
"validation_rule_id": "pan_format_v1",
"business_step": "PAN_ENTRY",
"validation_intent": "PAN_FORMAT",
"recovery_playbook_id": "retry_pan_01"
}Error Events
Generic error reporting:
AI.trackError(
code = "network_timeout",
properties = mapOf(
"endpoint" to "/api/submit",
"retry_count" to "3"
)
)Backend event: error_reported
Key fields:
{
"event": "error_reported",
"errors": ["network_timeout"],
"properties": {
"error_code": "network_timeout",
"endpoint": "/api/submit",
"retry_count": "3"
}
}Use for:
- Network failures
- UX issues
- Non-field errors
Field Naming Consistency
| Field | Meaning | Always Present |
|---|---|---|
user_id | Stable user identifier | Yes |
session_id | UUID per app session | Yes |
event | Ingestion event type | Yes |
timestamp | Unix seconds | Yes |
screen / screen_id | Current screen | When applicable |
component_id | UI component | Component events |
traceparent | W3C trace context | Recommended |
trace_id | Request correlation | Recommended |
Avoid Duplication
Keep one canonical location per datum:
- Don't duplicate
hintin multiple payload locations - Don't send both
screenandscreen_idwith same value - Use
propertiesonly for extensible metadata