# Trulioo Web SDK Guide

## Quick Summary

The Trulioo Web SDK initializes a shortcode-backed session and exposes base verification capabilities for browser applications.

Customer applications can expect the SDK to:

- resolve session configuration and authorization from the active shortcode
- collect Device Intelligence when the application flow is ready
- run KYC Data verification with subject data supplied by the application
- prepare and launch eID verification where configured
- return promise-based results, identifiers, errors, and diagnostic trace data for host routing and support

A standard web integration looks like this:

1. install `@trulioo/trulioo`
2. initialize with a shortcode
3. call `collectDeviceIntelligence(...)` or enable web auto-collection intentionally
4. optionally provide subject reference data
5. branch on accepted or failed and log `transactionId`, `eventId`, and `debugTrace`

## Package

- npm package: `@trulioo/trulioo`
- import entry point: `@trulioo/trulioo`

Supported Web integrations must use the Trulioo-supported runtime path for the current release.

- the Trulioo web SDK requires the encrypted payload bundle before it seeds `/device/intelligence/events`
- runtime paths that only return `eventId` are unsupported
- `eventId` remains part of the Trulioo device event model for polling and diagnostics after seed submission succeeds

## Installation

```bash
npm install @trulioo/trulioo
```

Example import:

```ts
import { Trulioo } from "@trulioo/trulioo";
```

Use the SDK from a CDN:

```javascript
import { Trulioo } from "https://cdn.trulioo.com/web/sdk/trulioo/latest/dist/esm/trulioo.js";
```

Use a pinned version instead of the latest package:

```javascript
import { Trulioo } from "https://cdn.trulioo.com/web/sdk/trulioo/VERSION_NUMBER/dist/esm/trulioo.js";
```

Replace `VERSION_NUMBER` with the SDK version you want to lock to.

## Runtime Requirement

Supported web integrations must use the Trulioo-supported runtime path for the current release.

- the default web path keeps runtime setup inside the Trulioo SDK
- if you enable `loadBundledDeviceBridge`, treat it as an SDK-owned runtime option rather than a separate public SDK
- do not integrate against private globals or undocumented browser callbacks

## Public API Surface

Main entry points:

- `Trulioo.initialize(...)`
- `Trulioo.collectDeviceIntelligence(...)`
- `Trulioo.getDeviceInformation(...)`
- `Trulioo.verifyData(...)`
- `Trulioo.prepareEid(...)`
- `Trulioo.verifyEid(...)`
- `Trulioo.sessionClient(...)`

Important types:

- `TruliooInitializationOptions`
- `TruliooInitializationHandlers`
- `TruliooInitializationResult`
- `TruliooSessionClient`
- `TruliooSessionClientOptions`
- `TruliooDeviceIntelligenceOptions`
- `DeviceIntelligencePollingOptions`
- `DeviceSubjectReference`
- `TruliooDebugTraceEntry`
- `DeviceReferenceOtherField`
- `AuthorizedPostEndpoint`
- `TruliooApiError`
- `TruliooTransportError`
- `TruliooTransportErrorCode`

## Transport Retries

By default, failed API calls are retried automatically.

- default retries: `3`
- total attempts: `4`
- `maxRetries` is an optional field that sets the number of automatic retries after an API call failure

Example:

```ts
await sessionClient.authorizedPost(endpoint, request, {
  maxRetries: 0,
});
```

## Initialization

Initialization returns a promise:

```ts
const initialized = await Trulioo.initialize(
  shortcode,
  {
    onComplete(result) {
      // Optional callback
    },
    onError(error) {
      // Optional callback
    },
  },
  {
    allowLocalDevelopment: false,
    sdkVersion: "1.0.0",
  },
);
```

### What Initialization Does

Initialization:

1. resolves the base host from the shortcode
2. performs challenge and authorization
3. fetches session configuration
4. returns the initialization result
5. may queue web auto-collection if requested

Initialization does not automatically mean the device event has completed unless you intentionally enabled web auto-collection behavior.

## Initialization Options

`TruliooInitializationOptions` supports:

- `allowLocalDevelopment?: boolean`
- `deviceIntelligence?: TruliooDeviceIntelligenceOptions`
- `fetch?: typeof fetch`
- `sdkVersion?: string`
- `runtime?: Partial<TruliooRuntimeMetadata>`

Use cases:

- `allowLocalDevelopment`
  Boolean. Enables local or emulator shortcode testing.
- `deviceIntelligence`
  Options object. Its presence enables web auto-collection behavior during initialization.
  Pass `{}` to opt in with defaults, or provide nested options.
- `fetch`
  Fetch override. Lets you provide a custom fetch implementation.
- `sdkVersion`
  String. Forwards the caller SDK version into runtime metadata.
- `runtime`
  Partial runtime metadata override. Lets you override browser-derived values such as locale or app identity when needed.

`TruliooDeviceIntelligenceOptions` supports:

- `fetch?: typeof fetch`
- `loadBridge?: DeviceSdkLoader`
- `polling?: DeviceIntelligencePollingOptions`
- `userId?: string`

`DeviceIntelligencePollingOptions` supports:

- `maxAttempts?: number`
- `intervalMs?: number`

Examples:

Initialize without auto-collection:

```ts
const initialized = await Trulioo.initialize(shortcode, {}, {
  allowLocalDevelopment: false,
  sdkVersion: "1.0.0",
});
```

Enable auto-collection with defaults:

```ts
const initialized = await Trulioo.initialize(shortcode, {}, {
  deviceIntelligence: {},
});
```

Enable auto-collection with custom DI options:

```ts
const initialized = await Trulioo.initialize(shortcode, {}, {
  deviceIntelligence: {
    userId: "customer-123",
    polling: {
      maxAttempts: 10,
      intervalMs: 1000,
    },
  },
  runtime: {
    locale: "en-US",
  },
});
```

Use `userId` only when your downstream device-intelligence runtime expects a runtime-specific user identifier. It is not a replacement for the Trulioo transaction ID or event ID.

## Features

Beta - changes are possible.

### Device Intelligence

Use Device Intelligence when your web flow needs device-risk telemetry from the current browser session.

The normal web sequence is:

1. initialize once
2. call `collectDeviceIntelligence(...)` when the host wants an explicit collection result
3. optionally use web auto-collection when background browser collection is preferred
4. inspect accepted or failed results

Explicit collection example:

```ts
const initialized = await Trulioo.initialize(shortcode);

const result = await Trulioo.collectDeviceIntelligence(initialized, {
  polling: {
    maxAttempts: 32,
    intervalMs: 1250,
  },
  reference: {
    firstName: "Jane",
    lastName: "Doe",
  },
});

console.log("device event", result.deviceEvent);
console.log("device seed", result.deviceSeed);
```

Debug example:

```ts
const initialized = await Trulioo.initialize(shortcode);

const debugResult = await Trulioo.collectDeviceIntelligence(initialized, {
  polling: {
    maxAttempts: 32,
    intervalMs: 1250,
  },
  reference: {
    firstName: "Jane",
    lastName: "Doe",
  },
});

console.log(debugResult.deviceEvent);
console.log(debugResult.deviceSeed);
```

Important behavior:

- `collectDeviceIntelligence(...)` is the documented explicit collection path
- `getDeviceInformation(...)` is useful when the host only needs the normalized device seed through callbacks
- `reference` is caller-owned subject data only
- device basic information is generated by the SDK
- the SDK requires the supported encrypted payload bundle path before it seeds the Trulioo device event
- `TruliooInitializationOptions.deviceIntelligence` and `handlers.onDeviceInformation` enable browser-specific auto-collection during initialization and should be used intentionally

## Debug Blocking Collection

Use blocking collection only when debug or diagnostics need the resolved device event and normalized seed:

```ts
const result = await Trulioo.collectDeviceIntelligence(initialized, {
  polling: {
    maxAttempts: 32,
    intervalMs: 1250,
  },
  reference: {
    firstName: "Jane",
    lastName: "Doe",
  },
});
```

## Optional Web Auto-Collection

The web SDK has a browser-specific auto-queue behavior.

It starts background device collection during initialization when either of these is provided:

- `handlers.onDeviceInformation`
- `options.deviceIntelligence`

This is useful in browser-first flows where background collection is desired, but it is not the only integration mode and should be enabled intentionally.

If you want the cleanest parity with native platforms, prefer explicit collection.

## Convenience Device Callback

If debug tooling only needs the normalized device result:

```ts
Trulioo.getDeviceInformation(
  initialized,
  (device) => {
    // device is DeviceSeedResponse | undefined
  },
  (error) => {
    // Collection failed
  },
);
```

## Polling

Default polling:

- `maxAttempts = 32`
- `intervalMs = 1250`

### KYC Data Verification

Use `Trulioo.verifyData(...)` when your web flow already has subject data and needs a terminal KYC verification result from the same shortcode-backed session.

The normal web sequence is:

1. initialize once
2. collect subject data in your app
3. call `Trulioo.verifyData(...)`
4. inspect the terminal result

Example:

```ts
const initialized = await Trulioo.initialize(shortcode);

const stopDataState = Trulioo.onDataStateChange((state) => {
  console.log("dataState", state);
});

const result = await Trulioo.verifyData({
  countryCode: "CA",
  personInfo: {
    firstName: "Jane",
    lastName: "Doe",
    dateOfBirth: "1990-01-01",
  },
  location: {
    buildingNumber: "123",
    streetName: "Example",
    streetType: "Ave",
    city: "Exampleville",
    stateProvinceCode: "BC",
    postalCode: "V0V0V0",
  },
  communication: {
    emailAddress: "jane.doe@example.com",
    mobileNumber: "+12025550123",
  },
});

stopDataState();

if (result.outcome === "ACCEPT" && result.recordMatch) {
  console.log("data verified", result.transactionId);
} else {
  console.log("data review path", result);
}
```

Important behavior:

- `verifyData(...)` reuses the internally stored initialized session
- the SDK submits PII but does not return PII in `DataVerificationResult`
- `Trulioo.dataState` exposes the current module state
- `Trulioo.onDataStateChange(...)` lets UI or observability code react to state changes
- `Trulioo.resetData()` cancels or clears the current data flow when you need to restart it

### eID Verification

Use the eID entrypoints when your web flow needs an interactive provider-backed identity verification from the same initialized session.

The normal web sequence is:

1. initialize once
2. optionally call `Trulioo.prepareEid(...)` when the eID screen becomes visible
3. call `Trulioo.verifyEid(...)` when the customer continues
4. inspect the terminal result or call `Trulioo.resetEid()` before retrying

Example:

```ts
const initialized = await Trulioo.initialize(shortcode);

const stopEidState = Trulioo.onEidStateChange((state) => {
  console.log("eidState", state);
});

await Trulioo.prepareEid({
  transactionId: initialized.configuration.transactionId,
  countryCode: "SE",
});

const eidResult = await Trulioo.verifyEid({
  transactionId: initialized.configuration.transactionId,
  countryCode: "SE",
});

stopEidState();

if (eidResult.outcome === "SUCCESS" && eidResult.match) {
  console.log("eid verified", eidResult.transactionId);
} else {
  console.log("eid not verified", eidResult);
}
```

Important behavior:

- web has no separate provider-listing or Auth Tab registration step
- `prepareEid(...)` is the right place to pre-warm the eID screen before the user launches the provider flow
- `verifyEid(...)` opens the interactive provider flow and waits for terminal status
- web eID configuration requires `transactionId`, which should come from `initialized.configuration.transactionId`
- `providerIdentifier` is optional and should only be passed when your journey needs to pin a specific provider
- `callbackOrigin` is optional and should only be set when your hosted callback flow requires an explicit origin override
- `Trulioo.eidState` exposes current eID progress
- `Trulioo.onEidStateChange(...)` lets the host UI react to preparation, launch, and processing states
- `Trulioo.resetEid()` clears interrupted eID state before a restart

## Advanced Authorized Session Contract

Web exposes the advanced post-bootstrap contract through `Trulioo.sessionClient(...)`.

Use this when your integration needs approved Trulioo routes after initialization, such as:

- typed authorized JSON requests
- typed authorized binary uploads

Create the client from a successful initialization result:

```ts
import { Trulioo } from "@trulioo/trulioo";

const initialized = await Trulioo.initialize(shortcode);

const sessionClient = Trulioo.sessionClient(initialized, {
  allowedEndpoints: ["/vendor/device/session", "/vendor/device/upload"],
});
```

The zero-argument helper only enables the base SDK's default device-owned post-bootstrap routes. Feature SDKs that own additional approved routes must register them explicitly through `allowedEndpoints`.

Available operations:

- `authorizedPost(endpoint, request, { maxRetries })`
- `authorizedGet(endpoint, { maxRetries })`
- `authorizedPostWithoutBody(endpoint, { maxRetries })`
- `authorizedPostWithoutResponse(endpoint, request, { maxRetries })`
- `authorizedGetWithoutResponse(endpoint, { maxRetries })`
- `authorizedUpload(endpoint, body, { headers, timeoutMs, maxRetries })`

Example typed authorized POST:

```ts
type StatusResponse = { status: string };

const status = await sessionClient.authorizedPost<{ transactionId: string }, StatusResponse>(
  { path: "/vendor/device/session" },
  { transactionId: "txn-123" },
);
```

Example typed upload:

```ts
const response = await sessionClient.authorizedUpload<{ transactionId: string }>(
  { path: "/vendor/device/upload" },
  imageBytes,
  {
    headers: {
      "Content-Type": "image/jpeg",
    },
  },
);
```

Rules:

- initialize first and reuse the returned initialization result
- the default helper only includes the base SDK's built-in device route allowlist
- register any extra approved routes explicitly through `allowedEndpoints`
- use approved relative paths only
- the session client owns the bearer token for you; do not pass `accessToken` into these calls
- handle `TruliooTransportError` for non-2xx failures; inspect the `code` field (`TruliooTransportErrorCode`) to branch handling rather than parsing `message`
- treat this as an advanced contract, not the default device-information integration path

## Subject Reference Data

The public web reference contract accepts subject data only:

```ts
const reference = {
  firstName: "Jane",
  lastName: "Doe",
  dateOfBirth: "1990-01-01",
  phoneNumber: "+15551234567",
  other: [{ customKey: "middleName", value: "Ann" }],
};
```

Do not provide device basic-information values from the application. The SDK builds those internally.

A runtime submit that does not return the encrypted payload bundle fails before Trulioo seed submission.

## Browser Runtime Metadata

By default, the web SDK derives runtime metadata from the browser:

- locale from `navigator.language`
- software from `navigator.userAgent`
- app domain from `location.hostname`

This metadata is used for initialization and for SDK-owned basic-information generation.

Use the `runtime` option only when you intentionally need to override browser-derived values.

## Results

`TruliooInitializationResult` contains:

- `baseUrl`
- `accessToken`
- `configuration`
- `deviceEvent`
- `deviceSeed`
- `debugTrace`

Use:

- `configuration` to confirm backend enablement
- `deviceEvent` as the source of truth for terminal status
- `deviceSeed` for normalized device data
- `debugTrace` for diagnostics

## Resetting State

Call `Trulioo.reset()` to clear all internal session state. Use this for logout flows, multi-session apps, or when re-initializing with a new shortcode:

```ts
Trulioo.reset();
// Can now call Trulioo.initialize(...) again with a new shortcode
```

Note: Calling any method other than `initialize(...)` after `reset()` will throw `TruliooNotInitializedError`.

## Error Handling

Not-initialized errors:

- `TruliooNotInitializedError` is thrown when calling any method before `initialize()` completes or after `reset()`
- Affected methods: `collectDeviceIntelligence`, `getDeviceInformation`, `verifyData`, `prepareEid`, `verifyEid`, `sessionClient`

Initialization errors:

- reject the initialization promise
- call `handlers.onError`, when provided

Send errors:

- return `status: "failed"` with a stable failure code, stage, message, and `debugTrace`

Collection errors:

- reject the collection promise when the debug wait path cannot resolve the terminal event

Reference submission failures:

- are recorded in `debugTrace`
- do not directly fail the main device event flow

Transport errors:

- `TruliooSessionClient` methods throw `TruliooTransportError` when an HTTP or network-level request fails
- inspect `error.code` (`TruliooTransportErrorCode`) to classify the failure — do not parse `error.message`, which is a diagnostic string for logging
- codes: `TIMEOUT`, `NO_INTERNET`, `SERVER_DOWN`, `BAD_REQUEST`, `UNAUTHORIZED`, `TOO_MANY_REQUESTS`, `UNPROCESSABLE_ENTITY`, `REQUEST_FAILURE`

```ts
try {
  const result = await sessionClient.authorizedPost<MyResponse>({ path: "/my/endpoint" });
} catch (error) {
  if (error instanceof TruliooTransportError) {
    switch (error.code) {
      case "TIMEOUT":      // retry or inform user
      case "NO_INTERNET":  // check connectivity
      case "UNAUTHORIZED": // re-initialize
      default:             // unexpected failure
    }
  }
}
```

## Environment And Shortcode Rules

Environment resolution is shortcode-driven.

| Shortcode Pattern | Environment |
| --- | --- |
| default | production |
| `.dv` suffix | development |
| `.pr` suffix | preview |
| `.local` suffix or `local` | local |
| `.emulator` suffix or `emulator` | emulator |
| `local@host:port` | local override |
| `emulator@host:port` | emulator override |

Supported region prefixes:

- `us`
- `eu`
- `ap` / `apac`
- `ca`

Local and emulator shortcodes are blocked unless `allowLocalDevelopment` is enabled.

## Common Mistakes

- assuming web auto-collection is always enabled
- using auto-collection accidentally because `deviceIntelligence` options were passed to initialization
- treating reference failure as the same thing as terminal event failure
- trying to pass basic device-information fields from the app
- enabling local shortcode routing without realizing it is blocked by default

## Troubleshooting

If device intelligence does not appear:

1. Confirm initialization completed successfully.
2. Confirm `configuration.deviceIntelligence?.enabled === true`.
3. Confirm the browser can load the configured device-intelligence runtime.
4. Confirm you either explicitly called send or intentionally enabled auto-collection.
5. Inspect `debugTrace`.

If results are incomplete:

1. inspect `deviceEvent?.failureReason`
2. inspect processor status if present
3. compare the terminal event outcome to `device_reference_submit`

## Diagnostic Capture Checklist

When capturing a web integration issue, record:

1. the shortcode used and whether it was production, development, preview, local, or emulator
2. whether the integration used fire-and-forget send, blocking collection for debug, or intentional auto-collection
3. whether `loadBundledDeviceBridge` was enabled or the default runtime path was used
4. the terminal `deviceEvent.status` and `failureReason`, if present
5. the `transactionId`, `eventId`, and relevant `debugTrace` entries
6. whether subject reference data was provided and whether `device_reference_submit` succeeded
7. browser name, browser version, and any custom `runtime` overrides
