Note
This guide is specific to Web SDK 2.0. If you are still using 1.x, you can find documentation here. Contact your Incode Representative for upgrade information and check if you are a candidate for this upgrade.
Full rollout to all clients still TBD.
Setup
setup()
Initialize the SDK before using any components.
Which setup() do I call?
You call one, never both. Two packages export a setup(), and @incodetech/web's version calls @incodetech/core's for you:
your app ──▶ setup() from '@incodetech/web' ──calls──▶ setup() from '@incodetech/core'
adds i18n, uiConfig, theme apiURL, token, wasm, encryption, …
your app ──▶ setup() from '@incodetech/core' (headless — the web layer is never loaded)
Start from what you render:
| You render | Call | Why |
|---|---|---|
| Your own UI, driving headless managers | setup() from @incodetech/core |
Nothing in the web layer needs configuring. |
| Web components, and you have the session token | setup() from @incodetech/web |
One call wires both layers, including language, branding, and the dashboard theme. |
Web components, but you need setup() before the token |
setup() from @incodetech/core |
The web wrapper requires token; core's does not. See the trade-off below. |
The web wrapper forwards every shared option to core unchanged, then adds i18n, uiConfig, and theme. Both entry points support flow; their feature-management option types differ as described below.
When you deliberately use core's setup() with web components
Two things pull integrators back to the core entry point even when they render components:
- You want
setup()to run before the session token exists, so WASM warmup overlaps with your back end creating the session. Core'ssetup()accepts optionalapiURLandtokenproperties.setup()pairs withinitializeSession(); the web wrapper requirestokenup front. - You need an option the web wrapper does not accept —
encryption,tri, ortrueSight. End-to-end encryption is the common case; see End-to-End Encryption.
That combination works, and the examples throughout these docs use it. Just wire the presentation layer yourself, because core's setup() cannot:
What web's setup() would have done |
Do this instead |
|---|---|
i18n — language and translations |
Call setI18nInstance(createI18n({ lang, translations })) from @incodetech/web. Text still renders without it, in English defaults. See Internationalization. |
uiConfig — logo, subtitle, assets, loader |
Call setUiConfig({ … }) from @incodetech/web. See Theming & Styling. |
theme — the dashboard theme |
<incode-flow> and <incode-workflow> fetch it themselves from their config.token, so they are unaffected. Standalone module components do not — they render unbranded. Apply your branding through setUiConfig instead. |
flow — Flow-backed standalone config |
Core accepts flow with the same preload and mergeConfig semantics. See Individual Modules. |
The silent case is worth repeating: a standalone <incode-selfie> or <incode-id> set up through core skips the dashboard theme with no error. If your branding comes from the Incode dashboard rather than setUiConfig, use the web setup().
setup() from @incodetech/core
import { setup } from '@incodetech/core';
await setup({
apiURL?: string; // API base URL
token?: string; // Session token (one-shot convenience — delegates to initializeSession)
customHeaders?: Record<string, string>;
timeout?: number; // Request timeout (ms). No deadline when omitted.
wasm?: WasmConfig | false; // WASM warmup (see WASM Configuration)
encryption?: boolean | { mgf1?: 'sha1' | 'sha256' }; // End-to-end encryption (locked at boot)
ipLookup?: boolean; // Default true. Set false to skip the third-party IP lookup (api.ipify.org).
fingerprint?: boolean; // Default true. Set false to skip device-fingerprint submission (transition flag).
flow?: false | { preload?: boolean; mergeConfig?: boolean }; // Flow-backed config for standalone modules
devMode?: boolean; // Default false. Use true only during local development.
tri?: { token: string; apiURL: string; autostart?: boolean }; // Optional TRI telemetry config
trueSight?: { enabled?: boolean }; // Temporarily unavailable; option accepted for compatibility.
featureManagement?: boolean | FeatureManagementSetupOptions; // Default true. Set false to opt out entirely.
environment?: 'development' | 'staging' | 'production'; // Default 'production'. Feature-management targeting only.
});
The canonical activation pattern is two calls — setup({ apiURL }) first, then initializeSession({ token }) once the session token is known. See initializeSession() below. Passing token to setup is a one-shot convenience that delegates to initializeSession internally.
| Option | Type | Required | Description |
|---|---|---|---|
apiURL |
string |
❌ | API base URL. Omit when every API actor is overridden via .provide() (advanced). |
token |
string |
❌ | Session token. One-shot convenience that delegates to initializeSession({ token }). Prefer the explicit two-call form: setup({ apiURL }) then initializeSession({ token }). The two-call form lets you start setup (including WASM warmup) before the token is known. |
customHeaders |
Record<string, string> |
❌ | Headers to attach to every SDK request. |
timeout |
number |
❌ | Request timeout in milliseconds. There is no default deadline — omit it and a request runs until it succeeds, fails at the network layer, or the API gateway ends it. That keeps large uploads alive on slow mobile connections, where a fixed timeout cut them off mid-transfer. Set this when your integration needs a bounded request. |
wasm |
WasmConfig | false |
❌ | WASM warmup. Omit to skip preload (loads lazily on first selfie/ID capture). Pass an object to warm up with CDN defaults plus any overrides. Pass false to explicitly disable. See WASM Configuration. |
encryption |
boolean | { mgf1?: 'sha1' | 'sha256' } |
❌ | Enable end-to-end encryption for SDK traffic. Independent of token — can be enabled before a session token is known. Not a self-serve flag — your Incode account team provisions the environment and gives you the dedicated apiURL and mgf1 scheme. Locked at boot (call reset() to change later) and requires the WASM binary transport. See End-to-End Encryption for the full walkthrough including API-key transmission, MGF1 schemes, and failure modes. |
ipLookup |
boolean |
❌ | Controls the third-party public-IP lookup (api.ipify.org). Default true (lookup enabled). Set false to opt out: no external call to ipify, at the cost of a less-precise fingerprint. Privacy-friendly for deployments where outbound calls to third-party services are restricted. |
fingerprint |
boolean |
❌ | Controls client-side device-fingerprint submission. Default true; set false to skip submission. With false, Flows and Workflows do not automatically add mandatory consent; your integration must handle any required consent. |
devMode |
boolean |
❌ | Development mode. Default false; use true only for local development; keep it false in production. WASM console logging is controlled separately by wasm.showLogs; see WASM Configuration. |
tri |
{ token: string; apiURL: string; autostart?: boolean } |
❌ | Transactional Risk Intelligence (TRI) telemetry. Provide token (an SDK token from createTRISession, not the org API key) and apiURL (the TRI ingest endpoint). TRI starts automatically unless autostart: false — use false to defer collection until after a consent gate, then call startTRI() from @incodetech/core/tri. Omitting this field opts out; no collectors start. |
flow |
false | { preload?: boolean; mergeConfig?: boolean } |
❌ | Controls whether standalone modules resolve their configuration from your Dashboard Flow. Omit it (or pass {}) for lazy resolution on mount. preload: true fetches flow during setup(). mergeConfig: true merges the config you supply over the flow config. false disables flow-backed resolution. See Individual Modules for the full matrix. |
trueSight |
{ enabled?: boolean } |
❌ | Diagnostics are temporarily unavailable in this release. The option remains accepted for compatibility, but enabled: true and server flags cannot activate collection or uploads. Regular SDK analytics are unaffected. |
featureManagement |
boolean | FeatureManagementSetupOptions |
❌ | Controls the feature-management integration, which decides gate and experiment values for the session. Enabled by default, loaded as a separate chunk, and served by a third party—see Third-Party Dependencies. Pass false for a full opt-out: no chunk, no feature-management network traffic. Reads from @incodetech/core/feature-management keep working when disabled and resolve to their defaults. Only the first enabling setup() initializes it. See the option table below. |
environment |
'development' | 'staging' | 'production' |
❌ | Coarse deployment tier used for feature-management targeting, with no finer granularity. Default 'production'. Read by the first enabling setup() only, and inert when featureManagement is false. |
FeatureManagementSetupOptions
Pass this object form instead of true to configure identity and privacy. The defaults are already conservative: no customer API key is used, and identity starts from an SDK-generated ID rather than anything you supply.
| Option | Type | Default | Description |
|---|---|---|---|
awaitInitialization |
boolean |
false |
Whether setup() waits for gate and experiment values to load before it resolves. By default, setup() resolves as soon as the HTTP client is ready (typically 150–250 ms sooner) while values load in the background; reads made before that settle return their defaults (status: 'uninitialized'). Await getIsFeatureManagementInitialized() when you need one that early, or set true to block setup() until they are loaded. <incode-flow>, <incode-workflow>, and the SDK's own modules are unaffected. |
clientExperimentId |
string |
— | Integrator-scoped targeting unit, agreed with your Incode representative. Use it to bucket gates for one integrator, such as a pilot rollout. |
disableStableId |
boolean |
false |
Stops the integration from generating a per-user ID at all. The strongest privacy control. Evaluations resolve to control values until session identity arrives later in the flow. |
disablePersistence |
boolean |
false |
Keeps identity in memory only, so it is never linkable across page loads. Trades away the local bootstrap cache, so every session fetches on boot. |
custom |
Record<string, unknown> |
— | Attributes attached for targeting rules and analytics. They do not bucket experiments. Keep personal data and secrets out—these reach the provider's logs as-is. |
redactedUserInfo |
FeatureManagementRedactedUserInfo |
ip, country redacted |
Which auto-collected fields to blank before they leave the browser. IP address and country are redacted by default; pass false for either to send it, or true for another field to redact that too. |
setup() from @incodetech/web
Use this one with the web components. apiURL and token are both required here, so create the session before you call it.
import { setup } from '@incodetech/web';
await setup({
apiURL: string; // Required
token: string; // Required: session token from createSession()
customHeaders?: Record<string, string>;
timeout?: number;
wasm?: WasmConfig | false;
ipLookup?: boolean;
fingerprint?: boolean;
devMode?: boolean;
featureManagement?: boolean | { clientExperimentId?: string; disableStableId?: boolean; disablePersistence?: boolean; redactedUserInfo?: FeatureManagementRedactedUserInfo };
environment?: 'development' | 'staging' | 'production';
i18n?: I18nOptions; // Language and translation overrides
uiConfig?: UiConfig; // Logo, subtitle, asset/animation and loader overrides
flow?: false | { preload?: boolean; mergeConfig?: boolean };
theme?: false | { preload?: boolean }; // Dashboard theme, independent of flow
});
| Option | Type | Required | Description |
|---|---|---|---|
apiURL |
string |
✅ | API base URL. |
token |
string |
✅ | Session token from createSession(). Unlike the core setup(), the web wrapper needs it up front. |
i18n |
I18nOptions |
❌ | Language selection and translation overrides. See Internationalization. |
uiConfig |
UiConfig |
❌ | Global branding and presentation: logo, subtitle, asset and animation overrides, loader presentation. See Asset Overrides and Theming & Styling. |
theme |
false | { preload?: boolean } |
❌ | Controls the dashboard theme independently of flow. Omit for lazy loading, { preload: true } to fetch and apply during setup(), or false to disable it. See Individual Modules. |
customHeaders, timeout, wasm, ipLookup, fingerprint, devMode, environment, flow |
same as core | ❌ | Forwarded to the core setup() unchanged — see the table above. |
Web setup accepts only clientExperimentId, disableStableId, disablePersistence, and redactedUserInfo in its feature-management object. Core additionally accepts custom, appVersion, and awaitInitialization. Use core setup when you need those fields, and configure presentation as described above; they are not accepted in a web setup object literal in 2.3.0.
createSession()
Create a verification session (call from your backend for production):
import { createSession } from '@incodetech/core/session';
const session = await createSession(apiKey, {
configurationId: string; // Required: Flow configuration ID from dashboard
language?: string; // Optional: Language code (e.g., 'en-US')
externalId?: string; // Optional: Your user reference ID
});
// Returns: { token: string; interviewId: string; ... }
initializeSession()
Activate a session by attaching the token to the HTTP client and pre-loading session-scoped state (feature flags, device fingerprint, analytics flush). Call once you have a session token — typically right after createSession() (or after your backend returns the token).
import { initializeSession } from '@incodetech/core/session';
await initializeSession({
token: string; // Required in application code: the session token from createSession()
signal?: AbortSignal; // Optional: abort the activation (e.g. on unmount)
preloadFlow?: boolean; // Optional: fetch the flow configuration alongside activation
awaitFingerprint?: boolean; // Optional: false resolves before the device fingerprint finishes (default true)
});
// Returns: { features, disableIpify, fingerprintSuccess, fingerprintResult }
| Option | Type | Required | Description |
|---|---|---|---|
token |
string |
✅ | Session token returned by createSession(). Application code should always pass this explicitly. |
signal |
AbortSignal |
❌ | Cancellation signal; useful for unmount-aborts in single-page apps. |
preloadFlow |
boolean |
❌ | Fetch the flow configuration in the same request wave as activation, so a later getFlow() or flow manager load() hits the cache. Default false. |
awaitFingerprint |
boolean |
❌ | false resolves as soon as the feature config is in and lets device-fingerprint submission finish in the background. fingerprintSuccess / fingerprintResult on the result are then not yet known; read them via whenSessionFingerprintSettled(). Default true. |
Results are cached per token: calling initializeSession again with the same token is a no-op; calling with a different token resets the cache and re-initializes from scratch. Idempotent across concurrent callers — a second in-flight call with the same arguments awaits the first.
whenSessionFingerprintSettled()
Use with to awaitFingerprint: false. Resolves with the DeviceFingerprintResult after the background fingerprint finishes, or undefined when fingerprinting failed or was skipped. Never rejects. If the fingerprint was already awaited, it resolves immediately with the cached result.
import { initializeSession, whenSessionFingerprintSettled } from '@incodetech/core/session';
const { features } = await initializeSession({ token, awaitFingerprint: false });
renderHome(features);
const fingerprint = await whenSessionFingerprintSettled();
if (fingerprint?.showMandatoryConsent) showConsent(fingerprint.regulationType);
Feature management
@incodetech/core/feature-management is the read surface for the gates, experiments, layers, and dynamic configs evaluated for the current session. The SDK handles initialization and identity itself during setup() and session activation — this subpath only reads. It ships as a separate subpath so integrations that never read a gate do not pay for it.
Incode agrees the gate and experiment keys with you; they are not self-serve.
import {
getFeatureGate,
getExperiment,
getLayer,
getFeatureDynamicConfig,
subscribeFeatureManagement,
} from '@incodetech/core/feature-management';
if (getFeatureGate('your_gate_key').enabled) {
// gated behavior
}
const experiment = getExperiment('your_experiment_key');
const variant = experiment.get('variantName', 'control');
const layer = getLayer('your_layer_key');
const timeoutMs = layer.get('timeoutMs', 10_000);
| Function | Returns | Description |
|---|---|---|
getFeatureGate(key) |
FeatureManagementGate |
Reads a boolean gate. Check .enabled. |
getExperiment(key) |
FeatureManagementExperiment |
Reads an experiment. Call .get(param, fallback) per parameter. |
getLayer(key) |
FeatureManagementLayer |
Reads a layer. Call .get(param, fallback) per parameter. |
getFeatureParameterStore(key, opts?) |
FeatureManagementParameterStore |
Reads a parameter store. |
getFeatureDynamicConfig(key) |
object or null |
Reads a dynamic config. |
subscribeFeatureManagement(fn) |
unsubscribe function | Notifies you when values change during the session, as identity is enriched. |
updateFeatureManagementUser(update) |
void |
Adds your own custom IDs to the evaluation identity. |
getIsFeatureManagementInitialized() |
boolean |
Whether initialization has finished. |
logEvent(...) |
void |
Records a custom event against the current identity. |
Every function here is graceful and none of them throw. setup() does not wait for gate and experiment values to load: it resolves as soon as the HTTP client is ready and the values arrive in the background, so a read made immediately after await setup() may still see the defaults below. When you need a real value that early, call await getIsFeatureManagementInitialized() first, or pass setup({ featureManagement: { awaitInitialization: true } }) to make setup() block until values are loaded. <incode-flow>, <incode-workflow>, and the SDK's own modules never need either: they read after the session identity update, which waits for loading itself. Before values load, and whenever setup({ featureManagement: false }) disabled the integration, reads resolve to documented defaults: gates return false, experiments and layers return your fallback, and dynamic configs return null. Code that reads a gate stays correct with the integration switched off, so you can disable it without branching.
Components
<incode-flow>
Complete verification flow as a standard Web Component.
// Side-effect import registers the custom element
import '@incodetech/web/flow';
import '@incodetech/web/flow/styles.css';
| Property | Type | Required | Description |
|---|---|---|---|
config |
FlowConfig |
✅ | Flow configuration object |
onFinish |
(result?: FinishStatus) => void |
✅ | Called when flow completes |
onError |
(error: string | undefined, errorCode?: number) => void |
❌ | Called when an error occurs |
FlowConfig
apiURL is configured via setup(), not in FlowConfig.
| Property | Type | Required | Description |
|---|---|---|---|
token |
string |
✅ | Session token from createSession() (token-based variant) |
apiKey (or clientId) + configurationId |
string |
✅ (alt) | Self-loading variant — component creates its own session. Avoid in production. |
lang |
string |
❌ | Language code (e.g. 'en-US') |
enableHome |
boolean |
❌ | Show the SDK's built-in home screen |
authHint |
string |
❌ | QR/auth hint when re-entering a flow |
redirectToMobileUrl |
string |
❌ | Override the destination URL for the Redirect to Mobile step |
urlUuid |
string |
❌ | QR anti-phishing token from URL |
injectCss |
boolean |
❌ | Opt into automatic Flow and lazy module stylesheet loading. Default false. Keep base/theme CSS imports. |
cssNonce |
string |
❌ | CSP nonce for stylesheets injected when injectCss is enabled. |
wasmConfig |
WasmConfig |
❌ | WASM configuration for ML features |
spinnerConfig |
SpinnerConfig |
❌ | Loading spinner customization |
disableDashboardTheme |
boolean |
❌ | Disable dashboard theme |
onFlowEvent |
(event: FlowEvent) => void |
❌ | Curated flow milestones |
onModuleLoading |
(moduleKey: string) => void |
❌ | Called when module starts loading |
onModuleLoaded |
(moduleKey: string) => void |
❌ | Called when module finishes loading |
onWasmWarmup |
(pipelines: string[]) => void |
❌ | Called when WASM warmup begins |
onUrlUuidRefreshed |
(urlUuid: string) => void |
❌ | New urlUuid available |
Other components
The SDK ships 20+ web components in addition to IncodeFlow — selfie, ID capture, phone, email, signature, consent, eKYC/eKYB orchestrators, and more. Rather than duplicate them here, see:
- Individual Modules: complete catalog of every web component and headless manager with import paths
- Web Components: tag-table reference for vanilla / framework-agnostic usage
- Module: Selfie, Module: ID, Module: Phone, Module: Email: deep-dive reference pages for the four most-used capture modules, including config tables, state machines, and full API surfaces
Headless Managers
Every module ships a corresponding createXxxManager factory for headless integrations. The full catalog (manager name, core import, what it does) lives in Individual Modules; detailed lifecycle, state, and method documentation for each manager lives in Headless Mode.
For the four most-used headless APIs, see:
- Module: Selfie § API Methods
- Module: ID § API Methods
- Module: Phone § API Methods
- Module: Email § API Methods
Legacy Flow manager
The manager also provides subscribeFlowEvent(listener) for curated milestones. It returns an unsubscribe function; see headless flow events for subscription and teardown.
createFlowManager() from @incodetech/core/flow loads a Flow and exposes manual step navigation. Prefer createOrchestratedFlowManager for automatic module orchestration.
| Method/Getter | Contract |
|---|---|
load() |
Start loading in idle. |
cancel() |
Cancel in loading, returning to idle. |
nextStep() |
Advance in ready; the last step reaches finished. |
prevStep() |
Move backward in ready when not on the first step. |
canNext |
True in ready when another step follows. False on the last step, although nextStep() can finish it. |
canPrev |
True in ready when a previous step exists. |
getModuleConfig<T>(moduleKey) |
Configuration for the named module, or undefined when absent or outside ready. |
isModuleEnabled(moduleKey) |
Whether the named module exists; false outside ready. |
reset() |
Return to idle from ready, error, or this legacy manager's non-final finished state. |
The modern orchestrator instead uses completeModule() and getModuleConfig<T>() for the current module; it has no legacy prevStep()/canPrev contract. Both support getState(), subscribe(), and stop().
See Also
- TypeScript Types: Type definitions
- Headless Mode: Detailed headless API
- Individual Modules: Complete module catalog