📘 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.
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
TypeScript
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' },
});
Subscribe to all events for custom logging or analytics:
TypeScript
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();
Sends a single event to the dashboard. Fire-and-forget - never blocks or throws.
TypeScript
addEvent({
code: 'captureAttemptFinished',
module: eventModuleNames.id,
screen: eventScreenNames.frontCameraCapture,
payload: { logs: [], attemptNumber: 1 },
clientTimestamp: Date.now(), // Optional, defaults to now
});
Parameters:
Field Type Required Description codestringYes Event code identifier moduleEventModule | stringNo Module name (use eventModuleNames constants) screenEventScreen | stringNo Screen name (use eventScreenNames constants) payloadRecord<string, unknown>No Additional event data clientTimestampnumberNo Timestamp in milliseconds (defaults to Date.now())
Subscribes to all SDK events for logging, debugging, or custom analytics. Returns an unsubscribe function.
TypeScript
const unsubscribe = subscribeEvent((event) => {
console.log('[Event]', event.code, event.module);
// Your custom logic here
});
// Later
unsubscribe();
Parameters:
Field Type Required Description listener(event: Event) => voidYes Callback 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.
TypeScript
// 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 });
TypeScript
import { eventModuleNames } from '@incodetech/core/events';
Constant Wire 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'
TypeScript
import { eventScreenNames } from '@incodetech/core/events';
Grouped by module for readability.
Constant Wire 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'
Constant Wire 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'
Constant Wire value eventScreenNames.mlConsent'MACHINE_LEARNING_CONSENT'eventScreenNames.combinedConsent'COMBINED_CONSENT'
Constant Wire 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'
Constant Wire value eventScreenNames.qrTutorial'QR_TUTORIAL'eventScreenNames.qrScan'QR_SCAN'
Constant Wire value eventScreenNames.smsOtp'OTP'eventScreenNames.simpleOTP'OTP' (alias)eventScreenNames.signatureInput'SIGNATURE_INPUT'
Constant Wire 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'
Constant Wire 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'
Constant Wire value eventScreenNames.passportTutorial'TUTORIAL_PASSPORT'
Constant Wire 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'
Constant Wire 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'
Constant Wire value eventScreenNames.conferenceWait'CONFERENCE_WAIT'eventScreenNames.conferenceVideoChat'CONFERENCE_VIDEO_CHAT'eventScreenNames.conferenceMessageChat'CONFERENCE_MESSAGE_CHAT'
Constant Wire 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'
Constant Wire value eventScreenNames.ekycInput'EKYC_INPUT'eventScreenNames.ekycProgress'EKYC_PROGRESS'eventScreenNames.ekycSucceeded'EKYC_SUCCEEDED'eventScreenNames.ekycFailed'EKYC_FAILED'eventScreenNames.ekybForm'EKYB_FORM'eventScreenNames.forms'FORMS'
Constant Wire 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'
Constant Wire value eventScreenNames.phoneInput'PHONE_INPUT'eventScreenNames.emailInput'EMAIL_INPUT'eventScreenNames.instantVerify'INSTANT_VERIFY'
Constant Wire value eventScreenNames.customModuleCallback'CUSTOM_MODULE_CALLBACK'eventScreenNames.customModuleProcessing'CUSTOM_MODULE_PROCESSING'
TypeScript
import { videoSelfieEvents } from '@incodetech/core/events';
Constant Wire 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'
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.
TypeScript
// 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
The SDK automatically sends these events from built-in modules:
Code Description When Sent moduleOpenedModule started When module component mounts moduleClosedModule ended When module component unmounts screenOpenedScreen displayed When screen component mounts screenClosedScreen hidden When screen component unmounts continueUser continued When user clicks continue/submit tutorialSelfieSelfie tutorial shown When selfie tutorial displays tutorialVideoStartedID tutorial video started When ID tutorial video plays captureAttemptFinishedCapture attempt completed After capture upload completes strSessionDidConnectRecording session connected When video recording starts strStreamVideoCaptureStartVideo capture started When video recording begins
TypeScript
import { addEvent, eventModuleNames } from '@incodetech/core/events';
function handleSubmit() {
addEvent({
code: 'customSubmitClicked',
module: eventModuleNames.phone,
payload: { timestamp: Date.now() },
});
// Your submit logic...
}
TypeScript
import { screenEvent, eventModuleNames, eventScreenNames } from '@incodetech/core/events';
function navigateToTutorial() {
screenEvent({
module: eventModuleNames.id,
screen: eventScreenNames.frontTutorial,
code: 'screenOpened',
});
// Navigate...
}
TypeScript
import { moduleOpened, moduleClosed, eventModuleNames } from '@incodetech/core/events';
function MyCustomPhoneFlow() {
useEffect(() => {
moduleOpened(eventModuleNames.phone);
return () => {
moduleClosed(eventModuleNames.phone);
};
}, []);
// Your custom implementation...
}
Use constants - Always use eventModuleNames and eventScreenNames instead of hardcoded strings
Fire-and-forget - Don't await addEvent() - it's designed to never block
Use hooks for lifecycle - Use useModuleEvents/useScreenEvents for automatic tracking
Include context - Add relevant data in payload for debugging
Don't track sensitive data - Never include PII or sensitive information in event payloads
Use subscribers for custom logging - Use subscribeEvent() for custom analytics or logging needs
Keep listeners lightweight - Event listeners are called synchronously; avoid heavy operations