# Track the ID and Face Validation Journey

Use onJourneyEvent to collect structured progress telemetry from the ID and Face Validation flow.

## Scope and provenance

- Product: web
- Status: Imported reference snapshot. Import date is not a verification date or guarantee of current release support.
- SDK version: Not declared for this page. Versions in examples must not be assumed current.
- Environment: Page-specific. Confirm the environment host, credentials, and service configuration; do not infer them from another product.
- Source: https://websdk2docs.idmission.com/customer-flows/id-and-face-validation-journey-events
- Imported at: 2026-10-21T17:27:01.149Z
- Canonical page: https://docs.idmission.com/web/customer-flows/id-and-face-validation-journey-events
- Agent index: https://docs.idmission.com/llms.txt

---

<a id="track-the-id-and-face-validation-journey"></a>

# Track the ID and Face Validation journey

The `onJourneyEvent` callback reports structured progress from the [`IdAndFaceValidation`](https://docs.idmission.com/markdown/web/customer-flows/id-and-face-validation.md) flow. Use it to answer questions such as:

- Did the user reach ID capture or face liveness?
- Which documents did the user capture?
- Did the user retry a capture?
- Which stages did the user complete?
- Did the user explicitly exit, and from where?

Journey events contain progress metadata only. They never contain captured images, document contents, submission requests, or validation responses.

<a id="add-the-callback"></a>

## Add the callback

```tsx
import {
  IdAndFaceValidation,
  type IdAndFaceValidationJourneyEvent,
} from "idmission-web-sdk";

function reportJourneyEvent(event: IdAndFaceValidationJourneyEvent) {
  analytics.track(event.name, event);
}

export default function App() {
  return (
    <IdAndFaceValidation
      sessionId={getSessionId}
      onJourneyEvent={reportJourneyEvent}
      onApproved={handleApproved}
      onDenied={handleDenied}
    />
  );
}
```

```js
IDmissionSDK.renderIdAndFaceValidation("#target-element", {
  sessionId: getSessionId,
  onJourneyEvent: (event) => {
    analytics.track(event.name, event);
  },
  onApproved: handleApproved,
  onDenied: handleDenied,
});
```

Every event has the same envelope:

```ts
type IdAndFaceValidationJourneyEventEnvelope = {
  version: 1;
  flow: "id-and-face-validation";
  timestamp: string; // ISO 8601 UTC timestamp
  name: string;
  [eventSpecificField: string]: unknown;
};
```

Use your own journey or analytics identifier to correlate events from a mounted flow instance. The `flow` field identifies the SDK flow type; it is not a unique instance ID.

<a id="event-reference"></a>

## Event reference

| Event               | Additional fields                     | When it is emitted                                                                                                         |
| ------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `flow.started`      | None                                  | Once, when the mounted flow begins reporting events. This is always the first journey event.                               |
| `stage.started`     | `stage`                               | When a stage becomes current, including its loading or introduction screen.                                                |
| `document.captured` | `stage: 'id-capture'`, `documentType` | When a document captured through the wizard is stored. Camera capture, fallback capture, and file upload are all included. |
| `selfie.captured`   | `stage`                               | When a selfie is accepted in face liveness or video signature capture.                                                     |
| `capture.retried`   | `stage`, optional `attempt`           | When the user chooses to retry a supported capture. `attempt` is included when the stage can supply it.                    |
| `stage.completed`   | `stage`                               | After a stage succeeds or is accepted and before the SDK advances to the next stage.                                       |
| `flow.exited`       | `reason`, optional `stage`            | When the user takes an SDK-provided explicit exit action. `stage` is included when the SDK knows it.                       |

<a id="stages"></a>

### Stages

| Value                         | Meaning                                          |
| ----------------------------- | ------------------------------------------------ |
| `id-capture`                  | Capture of the primary ID document.              |
| `face-liveness`               | Selfie and realness check.                       |
| `signature-capture`           | On-screen signature capture, when enabled.       |
| `video-signature-capture`     | Recorded selfie/signature capture, when enabled. |
| `additional-document-capture` | Additional document collection, when configured. |

<a id="document-types"></a>

### Document types

`document.captured` reports one of `idCardFront`, `idCardBack`, `passport`, or `singlePage`. Additional-document collection is represented by its stage events; it does not emit `document.captured` for each additional document.

<a id="exit-reasons"></a>

### Exit reasons

| Value          | Meaning                                                                         |
| -------------- | ------------------------------------------------------------------------------- |
| `capture-exit` | The user selected the exit control during ID, face, or video signature capture. |
| `failure-exit` | The user exited from the face-liveness failure experience.                      |
| `user-cancel`  | The user selected the cancel control on a loading or introduction screen.       |
| `tamper-exit`  | The user exited from the tamper-detection screen. The stage may be unknown.     |

Journey telemetry does not add or change exit controls. For example, `onUserCancel` must still be supplied for the cancel control to be shown, and `onExitAfterTamperSealPopped` must be supplied for the tamper-screen exit control to be shown. Continue to use those callbacks to navigate away or unmount the flow. A `flow.exited` event reports the action but does not close the flow by itself.

<a id="example-sequence"></a>

## Example sequence

A typical ID-card and face-liveness journey produces events in this order:

```text
flow.started
stage.started                  stage=id-capture
document.captured              stage=id-capture documentType=idCardFront
document.captured              stage=id-capture documentType=idCardBack
stage.completed                stage=id-capture
stage.started                  stage=face-liveness
selfie.captured                stage=face-liveness
stage.completed                stage=face-liveness
```

Configured optional stages appear in the same `stage.started` / `stage.completed` sequence. If an asynchronous `captureSignature` or `captureSignatureVideo` condition skips its stage, that stage still reports `stage.started` followed by `stage.completed`; there is no separate `stage.skipped` event.

The exact sequence depends on the flow configuration and user actions. For example, a passport journey emits one `document.captured` event with `documentType: 'passport'`, and a retry can insert `capture.retried` before the next capture event.

<a id="handle-event-variants-safely"></a>

## Handle event variants safely

The exported TypeScript event type is a discriminated union, so checking `event.name` narrows the event-specific fields:

```ts
import type { IdAndFaceValidationJourneyEvent } from "idmission-web-sdk";

function reportJourneyEvent(event: IdAndFaceValidationJourneyEvent) {
  switch (event.name) {
    case "document.captured":
      analytics.track("identity_document_captured", {
        documentType: event.documentType,
        occurredAt: event.timestamp,
      });
      break;

    case "capture.retried":
      analytics.track("identity_capture_retried", {
        stage: event.stage,
        attempt: event.attempt,
        occurredAt: event.timestamp,
      });
      break;

    case "flow.exited":
      analytics.track("identity_flow_exited", {
        stage: event.stage,
        reason: event.reason,
        occurredAt: event.timestamp,
      });
      break;

    default:
      analytics.track(event.name, event);
  }
}
```

Treat `attempt` and the exit event's `stage` as optional. Currently, face liveness retries provide an attempt number; ID and video signature retries do not.

<a id="journey-progress-versus-final-outcomes"></a>

## Journey progress versus final outcomes

`onJourneyEvent` describes what the user did inside the capture experience. It does not report the final validation decision and there is no `flow.completed` journey event. Keep the existing completion callbacks for business outcomes:

| What you need to observe                              | Callback                                                                                             |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| User progress, capture milestones, retries, and exits | `onJourneyEvent`                                                                                     |
| Completed SDK-managed submission only                 | `onComplete`                                                                                         |
| Approved validation                                   | `onApproved`                                                                                         |
| Denied validation                                     | `onDenied`                                                                                           |
| Submission failure                                    | `onRequestFailure`                                                                                   |
| Upload lifecycle and progress                         | `onBeforeDocumentUpload`, `onDocumentUploadProgress`, `onDocumentUploaded`, `onDocumentUploadFailed` |

Combining these callbacks gives you journey telemetry without treating a completed capture stage as a successful validation.

<a id="delivery-behavior"></a>

## Delivery behavior

Events are delivered synchronously and in causal order. The SDK does not wait for a returned promise. If the callback throws, the SDK logs the error and continues the capture journey.

Keep the handler fast. Enqueue or batch network work instead of blocking it, and handle delivery retries in your analytics client. The SDK does not buffer or replay events if the browser closes or the network is unavailable.

```ts
const pendingEvents: IdAndFaceValidationJourneyEvent[] = [];

function reportJourneyEvent(event: IdAndFaceValidationJourneyEvent) {
  pendingEvents.push(event);
  scheduleAnalyticsFlush();
}
```

<a id="precapture-and-abandonment-behavior"></a>

## Precapture and abandonment behavior

- Documents supplied through `precapturedDocuments` do not emit `document.captured`. A later recapture of the same document type does.
- A precaptured selfie can bypass face liveness and does not emit `selfie.captured`.
- Closing the tab, refreshing, losing power, or navigating away outside an SDK exit control does not emit `flow.exited`. If abandonment telemetry is required, add host-page lifecycle tracking such as `pagehide` and use `navigator.sendBeacon` where appropriate.

<a id="privacy-guidance"></a>

## Privacy guidance

Journey events are intentionally image-free, but they still describe identity verification activity. Send only the fields your telemetry system needs, use a customer-controlled correlation ID instead of personal data, and apply your organization's retention, consent, and access-control policies.
