Dashboard Events

The SDK provides a fire-and-forget event tracking system for sending telemetry to the Incode dashboard. This allows you to track module lifecycle, screen

📘

This guide is specific to Web SDK 2.0. If you are still using 1.x, you can find documentation here. We strongly recommend upgrading - contact your Incode Representative for upgrade information.

The SDK provides a fire-and-forget event tracking system for sending telemetry to the Incode dashboard. This allows you to track module lifecycle, screen transitions, and custom events throughout your verification flow.

Overview

Events are sent automatically by the SDK's built-in modules, but you can also track custom events from your own code. All events are:

  • Fire-and-forget: Never blocks execution, never throws errors
  • Headless-compatible: Available in @incodetech/core with zero UI dependencies
  • Auto-queued: Events sent before SDK is configured are queued and sent automatically when setup() is called

Quick Start

import { 
  addEvent, 
  moduleOpened, 
  moduleClosed,
  eventModuleNames 
} from '@incodetech/core/events';

// Track module lifecycle
useEffect(() => {
  moduleOpened(eventModuleNames.phone);
  return () => moduleClosed(eventModuleNames.phone);
}, []);

// Track custom events
addEvent({
  code: 'customButtonClicked',
  module: eventModuleNames.phone,
  payload: { buttonId: 'submit' },
});

Event Logging

Subscribe to all events for custom logging or analytics:

import { subscribeEvent } from '@incodetech/core/events';

// Custom logger - separate from API event sending
const unsubscribeLogger = subscribeEvent((event) => {
  console.log('[Event]', {
    code: event.code,
    module: event.module,
    screen: event.screen,
    payload: event.payload,
    timestamp: new Date(event.clientTimestamp ?? Date.now()).toISOString(),
  });
});

// Events are logged AND sent to API independently
addEvent({ code: 'test', module: 'PHONE' });
// → Logged to console via listener
// → Sent to API (automatic)

// Remove logger when done
unsubscribeLogger();

API Reference

Core Functions

addEvent(event)

Sends a single event to the dashboard. Fire-and-forget - never blocks or throws.

addEvent({
  code: 'captureAttemptFinished',
  module: eventModuleNames.id,
  screen: eventScreenNames.frontCameraCapture,
  payload: { logs: [], attemptNumber: 1 },
  clientTimestamp: Date.now(), // Optional, defaults to now
});

Parameters:

FieldTypeRequiredDescription
codestringYesEvent code identifier
moduleEventModule | stringNoModule name (use eventModuleNames constants)
screenEventScreen | stringNoScreen name (use eventScreenNames constants)
payloadRecord<string, unknown>NoAdditional event data
clientTimestampnumberNoTimestamp in milliseconds (defaults to Date.now())

subscribeEvent(listener)

Subscribes to all SDK events for logging, debugging, or custom analytics. Returns an unsubscribe function.

const unsubscribe = subscribeEvent((event) => {
  console.log('[Event]', event.code, event.module);
  // Your custom logic here
});

// Later
unsubscribe();

Parameters:

FieldTypeRequiredDescription
listener(event: Event) => voidYesCallback function that receives each event

Returns: Unsubscribe function to remove the listener

Note: Subscribers receive events before they're queued or sent to the API. Listener errors are silently caught and don't affect event sending.

Helper Functions

// Module lifecycle
moduleOpened(module, screen?, payload?);
moduleClosed(module, screen?, payload?);

// Screen lifecycle
screenOpened(module, screen, payload?);
screenClosed(module, screen, payload?);

// Generic screen event
screenEvent({ module, screen, code, payload });

Available Constants

Module Names

import { eventModuleNames } from '@incodetech/core/events';
ConstantWire value
eventModuleNames.selfie'SELFIE'
eventModuleNames.authentication'AUTHENTICATION'
eventModuleNames.authFace'AUTH_FACE'
eventModuleNames.mlConsent'ML_CONSENT'
eventModuleNames.combinedConsent'COMBINED_CONSENT'
eventModuleNames.curpValidation'CURP_VALIDATION'
eventModuleNames.faceMatch'FACE_MATCH'
eventModuleNames.qr'QR'
eventModuleNames.videoSelfie'VIDEO_ONBOARDING'
eventModuleNames.id'ID'
eventModuleNames.front'ID' (alias)
eventModuleNames.back'ID' (alias)
eventModuleNames.passport'ID' (alias)
eventModuleNames.idOcr'ID_OCR'
eventModuleNames.document'DOCUMENT_CAPTURE'
eventModuleNames.creditCard'CREDIT_CARD_FRONT'
eventModuleNames.creditCardBack'CREDIT_CARD_BACK'
eventModuleNames.conference'CONFERENCE'
eventModuleNames.otp'OTP'
eventModuleNames.signature'SIGNATURE'
eventModuleNames.ekyc'EXTERNAL_VERIFICATION'
eventModuleNames.watchlist'WATCHLIST'
eventModuleNames.globalWatchList'GLOBAL_WATCHLIST'
eventModuleNames.customWatchList'CUSTOM_WATCHLIST'
eventModuleNames.watchlistForBusiness'WATCHLIST_FOR_BUSINESS'
eventModuleNames.email'EMAIL'
eventModuleNames.phone'PHONE'
eventModuleNames.instantVerifyEmail'INSTANT_VERIFY_EMAIL'
eventModuleNames.instantVerifyConsent'INSTANT_VERIFY_CONSENT'
eventModuleNames.forms'FORMS'
eventModuleNames.customModule'CUSTOM_MODULE'
eventModuleNames.customFields'CUSTOM_FIELDS'
eventModuleNames.geolocation'GEOLOCATION'
eventModuleNames.ekyb'EKYB'
eventModuleNames.identityReuse'IDENTITY_REUSE'
eventModuleNames.antifraud'ANTIFRAUD'
eventModuleNames.aeSignature'AE_SIGNATURE'
eventModuleNames.qeSignature'QE_SIGNATURE'
eventModuleNames.crossDocumentDataMatch'CROSS_DOCUMENT_DATA_MATCH'

Screen Names

import { eventScreenNames } from '@incodetech/core/events';

Grouped by module for readability.

Selfie / Face Capture

ConstantWire value
eventScreenNames.faceCaptureTutorial'SELFIE_CAPTURE_TUTORIAL'
eventScreenNames.faceCaptureCamera'SELFIE_CAMERA_CAPTURE'
eventScreenNames.faceCaptureError'SELFIE_ATTEMPT_FAILED'
eventScreenNames.faceCaptureSuccess'SELFIE_UPLOAD_SUCCEEDED'
eventScreenNames.faceCaptureUpload'SELFIE_UPLOAD_PROGRESS'
eventScreenNames.faceMatch'FACE_MATCH'

Auth Face

ConstantWire value
eventScreenNames.authFace'AUTH_FACE'
eventScreenNames.authFaceTutorial'AUTH_FACE_TUTORIAL'
eventScreenNames.authFaceError'AUTH_FACE_ATTEMPT_FAILED'
eventScreenNames.authFaceUpload'AUTH_FACE_UPLOAD_PROGRESS'
eventScreenNames.authFaceUploadSuccess'AUTH_FACE_UPLOAD_SUCCEEDED'
eventScreenNames.authFaceUploadFailed'AUTH_FACE_UPLOAD_FAILED'

Consent

ConstantWire value
eventScreenNames.mlConsent'MACHINE_LEARNING_CONSENT'
eventScreenNames.combinedConsent'COMBINED_CONSENT'

CURP

ConstantWire value
eventScreenNames.curpEnter'ENTER_CURP'
eventScreenNames.curpValidate'VALIDATE_CURP'
eventScreenNames.curpGenerate'GENERATE_CURP'
eventScreenNames.curpValidation'CURP_VALIDATION_PROGRESS'
eventScreenNames.curpValidationFailed'CURP_VALIDATION_FAILED'
eventScreenNames.curpValidationSuccess'CURP_VALIDATION_SUCCEEDED'

QR

ConstantWire value
eventScreenNames.qrTutorial'QR_TUTORIAL'
eventScreenNames.qrScan'QR_SCAN'

OTP / Signature

ConstantWire value
eventScreenNames.smsOtp'OTP'
eventScreenNames.simpleOTP'OTP' (alias)
eventScreenNames.signatureInput'SIGNATURE_INPUT'

ID — Front

ConstantWire value
eventScreenNames.frontTutorial'FRONT_ID_CAPTURE_TUTORIAL'
eventScreenNames.frontCameraCapture'FRONT_ID_CAMERA_CAPTURE'
eventScreenNames.frontHelp'FRONT_ID_HELP'
eventScreenNames.frontReviewPhoto'FRONT_ID_REVIEW_PHOTO'
eventScreenNames.frontUploadProgress'FRONT_ID_UPLOAD_PROGRESS'
eventScreenNames.frontAttemptFailed'FRONT_ID_ATTEMPT_FAILED'
eventScreenNames.frontUploadSuccess'FRONT_ID_UPLOAD_SUCCEEDED'

ID — Back

ConstantWire value
eventScreenNames.backTutorial'BACK_ID_CAPTURE_TUTORIAL'
eventScreenNames.backCameraCapture'BACK_ID_CAMERA_CAPTURE'
eventScreenNames.backHelp'BACK_ID_HELP'
eventScreenNames.backReviewPhoto'BACK_ID_REVIEW_PHOTO'
eventScreenNames.backUploadProgress'BACK_ID_UPLOAD_PROGRESS'
eventScreenNames.backAttemptFailed'BACK_ID_ATTEMPT_FAILED'
eventScreenNames.backUploadSuccess'BACK_ID_UPLOAD_SUCCEEDED'

Passport

ConstantWire value
eventScreenNames.passportTutorial'TUTORIAL_PASSPORT'

Document Capture

ConstantWire value
eventScreenNames.documentTutorial'DOCUMENT_CAPTURE_TUTORIAL'
eventScreenNames.documentCameraCapture'DOCUMENT_CAMERA_CAPTURE'
eventScreenNames.documentHelp'DOCUMENT_HELP'
eventScreenNames.documentReviewPhoto'DOCUMENT_REVIEW_PHOTO'
eventScreenNames.documentUploadProgress'DOCUMENT_UPLOAD_IN_PROGRESS'
eventScreenNames.documentAttemptFailed'DOCUMENT_ATTEMPT_FAILED'
eventScreenNames.documentUploadSuccess'DOCUMENT_UPLOAD_SUCCEEDED'

Digital ID

ConstantWire value
eventScreenNames.digitalIdFileSelection'DIGITAL_ID_FILE_SELECTION'
eventScreenNames.digitalIdFileReview'DIGITAL_ID_FILE_REVIEW'
eventScreenNames.digitalIdUploadProgress'DIGITAL_ID_UPLOAD_PROGRESS'
eventScreenNames.digitalIdUploadSuccess'DIGITAL_ID_UPLOAD_SUCCEEDED'
eventScreenNames.digitalIdUploadFailed'DIGITAL_ID_UPLOAD_FAILED'
eventScreenNames.digitalIdAnalysisProgress'DIGITAL_ID_ANALYSIS_PROGRESS'
eventScreenNames.digitalIdVerificationSuccess'DIGITAL_ID_VERIFICATION_SUCCESS'
eventScreenNames.digitalIdVerificationFailed'DIGITAL_ID_VERIFICATION_FAILED'

Conference

ConstantWire value
eventScreenNames.conferenceWait'CONFERENCE_WAIT'
eventScreenNames.conferenceVideoChat'CONFERENCE_VIDEO_CHAT'
eventScreenNames.conferenceMessageChat'CONFERENCE_MESSAGE_CHAT'

Video Selfie

ConstantWire value
eventScreenNames.videoSelfieTutorial'VIDEO_SELFIE_TUTORIAL'
eventScreenNames.videoSelfie'VIDEO_SELFIE'
eventScreenNames.videoSelfieFaceCapture'VIDEO_SELFIE_FACE_CAPTURE'
eventScreenNames.videoSelfieFaceUploadProgress'VIDEO_SELFIE_FACE_UPLOAD_PROGRESS'
eventScreenNames.videoSelfieFaceAttemptFailed'VIDEO_SELFIE_FACE_ATTEMPT_FAILED'
eventScreenNames.videoSelfieFaceUploadSucceeded'VIDEO_SELFIE_FACE_UPLOAD_SUCCEEDED'
eventScreenNames.videoSelfieFrontIdCapture'VIDEO_SELFIE_FRONT_ID_CAPTURE'
eventScreenNames.videoSelfieFrontIdUploadProgress'VIDEO_SELFIE_FRONT_ID_UPLOAD_PROGRESS'
eventScreenNames.videoSelfieFrontIdAttemptFailed'VIDEO_SELFIE_FRONT_ID_ATTEMPT_FAILED'
eventScreenNames.videoSelfieFrontIdUploadSucceeded'VIDEO_SELFIE_FRONT_ID_UPLOAD_SUCCEEDED'
eventScreenNames.videoSelfieBackIdCapture'VIDEO_SELFIE_BACK_ID_CAPTURE'
eventScreenNames.videoSelfieBackIdUploadProgress'VIDEO_SELFIE_BACK_ID_UPLOAD_PROGRESS'
eventScreenNames.videoSelfieBackIdAttemptFailed'VIDEO_SELFIE_BACK_ID_ATTEMPT_FAILED'
eventScreenNames.videoSelfieBackIdUploadSucceeded'VIDEO_SELFIE_BACK_ID_UPLOAD_SUCCEEDED'
eventScreenNames.videoSelfieDocumentCapture'VIDEO_SELFIE_DOCUMENT_CAPTURE'
eventScreenNames.videoSelfieVoiceQuestion'VIDEO_SELFIE_VOICE_QUESTION'
eventScreenNames.videoSelfieVoiceFinalQuestion'VIDEO_SELFIE_VOICE_FINAL_QUESTION'
eventScreenNames.videoSelfieVideoUpload'VIDEO SELFIE VIDEO UPLOAD'

eKYC / eKYB / Forms

ConstantWire value
eventScreenNames.ekycInput'EKYC_INPUT'
eventScreenNames.ekycProgress'EKYC_PROGRESS'
eventScreenNames.ekycSucceeded'EKYC_SUCCEEDED'
eventScreenNames.ekycFailed'EKYC_FAILED'
eventScreenNames.ekybForm'EKYB_FORM'
eventScreenNames.forms'FORMS'

Watchlists

ConstantWire value
eventScreenNames.globalWatchListInput'GLOBAL_WATCHLIST_INPUT'
eventScreenNames.globalWatchListProgress'GLOBAL_WATCHLIST_PROGRESS'
eventScreenNames.globalWatchListSuccess'GLOBAL_WATCHLIST_SUCCEEDED'
eventScreenNames.globalWatchListFailed'GLOBAL_WATCHLIST_FAILED'
eventScreenNames.customWatchListInput'CUSTOM_WATCHLIST_INPUT'
eventScreenNames.customWatchListProgress'CUSTOM_WATCHLIST_PROGRESS'
eventScreenNames.customWatchListSuccess'CUSTOM_WATCHLIST_SUCCEEDED'
eventScreenNames.customWatchListFailed'CUSTOM_WATCHLIST_FAILED'

Phone / Email / Instant Verify

ConstantWire value
eventScreenNames.phoneInput'PHONE_INPUT'
eventScreenNames.emailInput'EMAIL_INPUT'
eventScreenNames.instantVerify'INSTANT_VERIFY'

Custom Module

ConstantWire value
eventScreenNames.customModuleCallback'CUSTOM_MODULE_CALLBACK'
eventScreenNames.customModuleProcessing'CUSTOM_MODULE_PROCESSING'

Video Selfie Events

import { videoSelfieEvents } from '@incodetech/core/events';
ConstantWire value
videoSelfieEvents.imageTooBlurry'imageTooBlurry'
videoSelfieEvents.fillFrame'fillFrame'
videoSelfieEvents.checkCameraOrLighting'checkCameraOrLighting'
videoSelfieEvents.frontIdCaptureStarted'frontIdCaptureStarted'
videoSelfieEvents.lookAtCamera'lookAtCamera'
videoSelfieEvents.moveCloser'moveCloser'
videoSelfieEvents.lookingForFrontId'lookingForFrontId'
videoSelfieEvents.lookingForBackId'lookingForBackId'
videoSelfieEvents.cameraSwitchToBack'cameraSwitchToBack'
videoSelfieEvents.cameraSwitchToFront'cameraSwitchToFront'
videoSelfieEvents.audioStreamOpened'audioStreamOpened'
videoSelfieEvents.audioStreamClosed'audioStreamClosed'
videoSelfieEvents.videoSelfieVideoUploadInProgress'videoSelfieVideoUploadInProgress'
videoSelfieEvents.videoSelfieTosNotAccepted'videoSelfieTosNotAccepted'
videoSelfieEvents.videoSelfieTosAccepted'videoSelfieTosAccepted'
videoSelfieEvents.videoSelfieStreamCreated'videoSelfieStreamCreated'
videoSelfieEvents.videoSelfieStreamDestroyed'videoSelfieStreamDestroyed'
videoSelfieEvents.videoSelfieReconnecting'videoSelfieReconnecting'
videoSelfieEvents.videoSelfieReconnected'videoSelfieReconnected'

Event Queue

Events sent before the SDK is configured (before setup() is called with a token) are automatically queued. When setup() is called with a token, all queued events are automatically flushed and sent.

// This event will be queued
addEvent({ code: 'sdkLoading', payload: { timestamp: Date.now() } });

// Later, after setup with token
await setup({ apiURL: '...', token: 'session-token' });
// ^ Queued events are automatically sent here

Common Event Codes

The SDK automatically sends these events from built-in modules:

CodeDescriptionWhen Sent
moduleOpenedModule startedWhen module component mounts
moduleClosedModule endedWhen module component unmounts
screenOpenedScreen displayedWhen screen component mounts
screenClosedScreen hiddenWhen screen component unmounts
continueUser continuedWhen user clicks continue/submit
tutorialSelfieSelfie tutorial shownWhen selfie tutorial displays
tutorialVideoStartedID tutorial video startedWhen ID tutorial video plays
captureAttemptFinishedCapture attempt completedAfter capture upload completes
strSessionDidConnectRecording session connectedWhen video recording starts
strStreamVideoCaptureStartVideo capture startedWhen video recording begins

Examples

Track Custom Button Click

import { addEvent, eventModuleNames } from '@incodetech/core/events';

function handleSubmit() {
  addEvent({
    code: 'customSubmitClicked',
    module: eventModuleNames.phone,
    payload: { timestamp: Date.now() },
  });
  
  // Your submit logic...
}

Track Screen Transition

import { screenEvent, eventModuleNames, eventScreenNames } from '@incodetech/core/events';

function navigateToTutorial() {
  screenEvent({
    module: eventModuleNames.id,
    screen: eventScreenNames.frontTutorial,
    code: 'screenOpened',
  });
  
  // Navigate...
}

Track Module Lifecycle in Headless Mode

import { moduleOpened, moduleClosed, eventModuleNames } from '@incodetech/core/events';

function MyCustomPhoneFlow() {
  useEffect(() => {
    moduleOpened(eventModuleNames.phone);
    
    return () => {
      moduleClosed(eventModuleNames.phone);
    };
  }, []);
  
  // Your custom implementation...
}

Best Practices

  1. Use constants - Always use eventModuleNames and eventScreenNames instead of hardcoded strings
  2. Fire-and-forget - Don't await addEvent() - it's designed to never block
  3. Use hooks for lifecycle - Use useModuleEvents/useScreenEvents for automatic tracking
  4. Include context - Add relevant data in payload for debugging
  5. Don't track sensitive data - Never include PII or sensitive information in event payloads
  6. Use subscribers for custom logging - Use subscribeEvent() for custom analytics or logging needs
  7. Keep listeners lightweight - Event listeners are called synchronously; avoid heavy operations

See Also