Release notes, Releases Web SDK

Web SDK 2.0 Release Notes

Every published release of the Incode Web SDK 2.x packages, newest first.

@incodetech/core and @incodetech/web are versioned in lock-step — a given release number always refers to both packages, and they must be installed at matching versions. New integrations should start from Getting Started.

npm install @incodetech/web@latest @incodetech/core@latest

Info

Looking for Web SDK 1.x? Its release notes are on

Web SDK Release Notes. The 1.x (@incodetech/welcome) and 2.x package lines are versioned independently.

2.2.0 — 2026-08-21

Added

  • Asset overrides — replace the built-in SVG illustrations and Lottie animations by key. Set assets and animations on UiConfig globally, or on FlowConfig and any module component's config for one element; per-instance wins over global wins over the built-in default. An override takes a URL, raw SVG markup, a precompiled SVG component, or Lottie JSON, and falls back to the default if it fails. Accessibility metadata always comes from the SDK, not your input. New types: AssetKey, AnimationKey, AssetOverride, AnimationOverride, AssetOverrides, AnimationOverrides, SvgComponent. See Asset Overrides.
  • Loader presentation controlspinner?: SpinnerPresentation on UiConfig globally, and on FlowConfig, WorkflowComponentConfig, and any module component's config per instance. It carries renderMode ('spinnerAndText' | 'spinnerOnly' | 'textOnly') and size. One global setting now reaches module-internal loaders — ID camera preparation, camera permissions — that a flow-level setting never reached. New types: SpinnerConfig, SpinnerPresentation, SpinnerRenderMode.
  • Feature managementsetup({ featureManagement, environment }) lets the SDK evaluate Incode-managed feature gates, experiments, layers, and parameter stores. Enabled by default; pass featureManagement: false to skip it, and no third-party code is fetched. Identity is anonymous by default — no API key is sent, the stable device ID and cross-page persistence are off, and ip and country are redacted. Configure with clientExperimentId, disableStableId, disablePersistence, custom, appVersion, and redactedUserInfo. Reads live on @incodetech/core/feature-management and never throw — they fall back to the default you pass. This adds the Statsig browser client, loaded lazily and only when enabled. See Third-Party Dependencies.
  • setup({ trueSight: { enabled: false } }) opts the session out of Incode SDK-health diagnostics, which are enabled by default.
  • setup({ flow }) and setup({ theme }) control what a standalone module loads up front. flow: false skips flow prefetch and config merging, flow: { preload, mergeConfig } enables each on its own; theme: false disables the session theme, theme: { preload: true } fetches it during setup(). See Individual Modules.
  • US Smart Capture reads the ID barcode end-to-end, matching 1.x. On-device barcode scanning runs alongside back-of-ID capture, and a back-only US ID can skip front capture, ID processing, and Face Match. If no barcode is read, capture falls back to the normal back-of-ID upload. See ID Capture.
  • Document Capture gains an onlyPdf flag that restricts uploads to PDF files, plus method-selection and common-issues screens. See Document Capture.
  • Dynamic Forms gains prefill and login-hint handling. See Dynamic Forms.
    • prefillValue on DynamicFormsConfig, and loginHintPrefill on FlowBaseConfig and WorkflowBaseConfig, seed the single answer of a one-screen, one-question form — a login hint your page reads from a URL parameter, for example. The field stays editable, and a multi-field form is never touched.
    • A question with prefillSource is populated from the customer's captured ID. Question gains prefillSource and editable, and the inputting and submitting states gain prefilledQuestionIds and nonEditableQuestionIds. Non-editable prefilled fields render read-only with a "from ID" marker and still submit. PHONE and MULTISELECT are excluded; an unresolved value stays blank and editable.
    • An invalid login hint shows an inline field error so the customer retries in place. Exhausted attempts park the module on a terminal screen, adding attemptsExhausted to DynamicFormsState.
  • Geolocation gains maxAttempts (default 3), retry() and quit() manager methods, and error and noNetwork states. Device failures no longer all report as permission denied — a timeout or unavailable position now routes to a retryable screen. @incodetech/web/extensibility exports a shared ConnectionError screen. See Geolocation.
  • Headless ID capture can render the optimizing phase. Declare IdCaptureConfig.supportsOptimizingStatus when you render captureStatus === 'optimizing' from candidateImageUrl ?? previewImageUrl. 'optimizing' joins the captureStatus union, and capture state gains candidateImageUrl (display only) and optimizingDwellMs. Leave the flag unset and the phase never runs. See Headless Mode.
  • @incodetech/web/government-validation and its /styles.css subpath export, so the module can be imported standalone like the others. See Individual Modules.
  • Design system (@incodetech/web/extensibility): PasswordInputComposed, a password field with a show/hide toggle and an optional requirements checklist you supply results for; an invalid prop on InputComposed that sets aria-invalid without a message; and textSize ('M' | 'S') on RadioButtonComposed.
  • --input-surface-hover and --dropdown-surface-hover tokens drive the hover state on inputs and dropdowns. See Theming and Styling.

Changed

  • captureMode semantics changed in Document Capture. 'camera' is now capture-only, where it previously offered both. Omit captureMode to keep capture plus upload with a method selector. 'file' remains upload-only. See Document Capture.
  • Selfie and Authentication concealment uses one field. selfieConcealmentOption ('OPTION_NONE' | 'OPTION_SILHOUETTE' | 'OPTION_2D' | 'OPTION_3D') on BaseFaceCaptureConfig and the SELFIE / AUTHENTICATION flow config replaces obfuscateWithAvatar and avatarVariant. Flows and workflows read it from your dashboard node configuration; standalone integrations set it directly. The avatar stays cosmetic — detection, quality, liveness, and upload run on the real frames.
  • Face Match is skipped when the ID has no front portrait. Under US Smart Capture, a back-only ID gives nothing to compare, so Face Match self-completes rather than running a match that cannot succeed. Flow and workflow now agree. Selfie capture is unaffected.
  • PermissionStatus gained 'checking', distinct from 'idle'. If you switch exhaustively on it, render nothing for 'checking'. Reading the value needs no change.
  • Two CSS class names are namespaced: SignatureCanvas*IncodeSignatureCanvas*, and ImageDocumentCapturePdfPreview*IncodeImageDocumentCapturePdfPreview*. Update your selectors if you target either. See Theming and Styling.
  • documentCapture.* analytics screen names were realigned. Re-check your mappings against Dashboard Events if you key logic off screen names.
  • Dynamic Forms and CURP Validation desktop layouts put fields in a contained scroll region with the button in a fixed footer, matching ID OCR and eKYB. Mobile is unchanged. Dynamic Forms no longer submits on Enter, also matching ID OCR and eKYB.
  • A non-repeatable flow whose session already finished no longer starts. It shows the localized finished-session screen and reports SESSION_FINISHED through the flow error callback.
  • Video Selfie follows the current design end to end. ID capture starts detecting immediately, wrong-side and success feedback render in the frame, camera switches get a full-screen transition, and the final screen releases camera and microphone first. The recording manager exposes flippingId and success. Each step allows three validation attempts; exhausting an ID side skips the remaining ID steps. Camera, network, and upload failures no longer consume an attempt or end the recording — call manager.retry(). See Video Selfie.
  • Video Selfie errors and uploads are more resilient. Error screens show translated copy instead of raw network detail, with the raw message kept on state.error. The recording streams in retried chunks, so an interruption salvages all but the final seconds. A failed selfie upload retries in place, then re-runs only the selfie step inside the same recording.
  • Redirect to Mobile applies a 30-second cooldown before an SMS link can be resent, and shows an error state when sending fails. See Redirect to Mobile.

Fixed

  • Camera permission is no longer requested on every capture module inside an Android WebView. A WebView has no persistent permission store, so the "allow camera" screen reappeared before each module even though no system prompt followed. The screen also no longer flashes during a permission check. iOS WebKit and Firefox for Android genuinely re-prompt, so they are unchanged.
  • The published stylesheets no longer style your page. Unscoped utility selectors (.flex, .container, .rounded) collided with integrator design systems; every published selector is now anchored to an Incode-namespaced class, attribute, or element, enforced by a build check. Dead CSS goes with it — base.css drops from 464 KB to 392 KB, flow/styles.css from 256 KB to 156 KB. See Bundle Optimization.
  • Three stylesheet subpaths resolved to files that were never built. Importing @incodetech/web/signature/styles.css, .../electronic-signature/styles.css, or .../qe-signature/styles.css failed in every bundler, as the module docs instruct. All three resolve now, and the electronic-signature family shares one stylesheet. No import path changed.
  • config.onlyFront reaches the backend. The ID module dropped it silently. It is now sent on the front upload, and the SDK honors the answer — onlyFront is a statement about the document that the server may decline, so a two-sided document still asks for the back, passports included. Use your dashboard's front-only configuration to force front-only capture. Manual upload hides the back slot after the front file alone, matching 1.x. See ID Capture.
  • Global asset and animation overrides were silently discarded by <incode-flow>, <incode-workflow>, and standalone modules. An override that fails at runtime now falls back to the built-in default instead of rendering blank, URLs are validated, and unknown keys warn in development.
  • ID Capture: capture works in Firefox for Android; the frame and preview respect a detected passport's orientation; "Unable to process" appears when Document Capture attempts are exhausted; and the selfie Age Assurance notice appears even when showTutorial is false, since that copy doubles as the age-estimation privacy notice.
  • Preview mirroring follows the camera actually opened, via a new usingBackCamera capture-state flag rather than the static assistedOnboarding config. A desktop without a rear camera now shows a mirrored front-camera view; mobile keeps the unmirrored rear view.
  • Privacy Lens and the 2D avatar are usable on low-tier devices. They render in a dedicated worker on Chromium browsers, with an improved main-thread fallback elsewhere, and no longer judder during capture. Avatar initialization also works in webpack-bundled apps, where it previously always failed.
  • Workflow: the launch "Get Started" screen reopens on desktop after leaving an injected Redirect to Mobile step, instead of jumping into the first module.
  • Shared components: the error icon on inputs, checkboxes, radio buttons, and phone, date, and textarea fields returns to its intended size; loaders use the default light secondary spinner color again; a long localized camera-permission title no longer overlaps the desktop modal close button; and Face Match no longer scrolls the page during its animations.
  • Accessibility (WCAG 2.2 AA) across Document Capture, Electronic Signature, Redirect to Mobile, and shared components: preview images and the PDF viewer gain accessible names and a real reading path; focus is restored across review states and after closing a document; camera pages expose landmarks and correct headings; help opens in a dialog that keeps assistive technology out of the background; consent links are underlined and meet contrast minimums; the phone field reports as required and identifies its autocomplete purpose; and searchable dropdowns expose their filter as an editable combobox.
  • Antifraud and device-integrity hardening.

Deprecated

  • SpinnerConfig.title and SpinnerConfig.subtitle. Set loader copy through the loadingCircle.* i18n translations instead — a literal string in config does not follow a runtime language change. Still honored in 2.2.0; removal targeted for 2.3.0. See Internationalization.

Removed

  • The CPF_OCR flow key and the @incodetech/core/cpf-ocr, @incodetech/web/cpf-ocr, and @incodetech/web/cpf-ocr/styles.css subpath exports. CPF-only capture is part of ID OCR now: a flow using useCPF keeps its ID_OCR step, preserves its configuration, and enables cpfOnly. Import formatCPF and isValidCPF from @incodetech/core/id-ocr. See ID OCR.
  • state.debugFrame from SelfieState, AuthenticationState, and IdCaptureState. It was already always undefined. If you need per-frame pipeline frames, contact us — a purpose-built, opt-in hook is the intended replacement.
  • The Geolocation manager's reset() method and its RESET event. No state handled the event, so no behavior is lost, but drop the call if you make it.

Install: npm install @incodetech/web@2.2.0 @incodetech/core@2.2.0

2.1.1 — 2026-07-30

Changed

  • @incodetech/core and @incodetech/web now publish ISC license metadata and a LICENSE file, so automated license scanners resolve the packages instead of rejecting them for missing license information. Metadata only — no API or runtime behavior changes.
  • Updated the bundled on-device processing runtime.

Fixed

  • The SDK now initializes on hardened hosts and in webviews where Web Storage is unavailable — removed, blocked, or replaced. Values that cannot be persisted are skipped and reads fall back to defaults, instead of the SDK failing to start.
  • Antifraud, device-integrity, and anti-injection hardening.

Install: npm install @incodetech/web@2.1.1 @incodetech/core@2.1.1

2.1.0 — 2026-07-10

Added

  • Certificate Issuance module (CERTIFICATE_ISSUANCE) — password capture, digital certificate issuance, and download. Available as createCertificateIssuanceManager from @incodetech/core/certificate-issuance and as <incode-certificate-issuance>. See Certificate Issuance.
  • Fiscal QR module (FISCAL_QR) — scans a Mexican fiscal (SAT) QR code, resolves its URL, and submits it for verification.
  • Field Comparison module (FIELD_COMPARISON) — collects a first and last name and submits them for backend verification.
  • INE Validation (INE_VALIDATION) — the Mexican government / INE check, available through the same manager and component as Government Validation.
  • ML Consent (ML_CONSENT) — supported in both flows and workflows through the shared mandatory
    consent module.
  • Video Selfie with local recording.
  • Privacy Lens — an opt-in cosmetic avatar rendered in place of the live camera preview during selfie and authentication capture, with a reassurance banner above the capture frame. Detection, quality, liveness, and upload continue to run on the real camera frames; enable it from your dashboard configuration.
  • setup() gained options for controlling third-party dependencies and self-hosting:
    • fingerprint: false — skips client-side device-fingerprint submission.
    • ipLookup: false — skips the client IP lookup.
    • i18n — supply your own i18n instance (@incodetech/web).
    • wasm: { basePath } — serve the on-device processing assets from your own origin. See WASM Configuration.
    • devMode and wasm: { showLogs } — development diagnostics. Do not enable in production.
  • extractIdFace: false on IdCaptureConfig skips face extraction from the ID document, for flows that do not run a biometric comparison. See ID Capture.
  • showFinishScreenBySessionStatus on the workflow configuration renders a finish screen specific to the resolved session status. See Workflow.
  • ID Capture and Face Capture emit new events:
    • errorTriggered for every front-end error state — capture and upload errors, expired document, offline or degraded network, and fatal errors — with an { errorName, errorCode, reason } payload.
    • background and foreground when the page's visibility changes during an active session, carrying the current screen. A session opened in an already-hidden tab reports it on start. See Event Callbacks.
  • Form modules expose per-field validation. validateField() on the manager triggers validation for a single field on blur, and a validationErrors map on the state drives the displayed messages. Available on eKYC, eKYB, Dynamic Forms, ID OCR, and CURP Validation.
  • Flow and workflow failures now carry a machine-readable moduleErrorCode, and Incode API error codes and messages are surfaced across the flow and workflow lifecycle.
  • A flow's onFinish result includes the end-screen texts configured in your dashboard.
  • eKYC renders phone and email fields when riskAddons are configured.
  • Dynamic Forms renders YESNO questions as a Yes/No dropdown.
  • <incode-workflow> supports a self-loading mode.
  • Watchlist, Watchlist for Business, and Incode Watchlist nodes now resolve in workflows.
  • Transactional Risk Intelligence (TRI) telemetry.

Changed

  • Forms use optimistic validation. The Continue button starts enabled on each screen. Submitting with empty required fields reports every missing field at once and disables the button until they are corrected; typing clears the error for that field. Format errors (phone, email, CPF, CNPJ, SSN, postal code) report on blur. Applies to eKYC, eKYB, Dynamic Forms, ID OCR, the phone and email input screens, and the OTP code screens.
  • Form state shape changed with it. If you read form state directly:
    • errors is replaced by validationErrors, whose entries are { key, params? }.
    • submitAttempted is removed — the state machine now writes errors for all invalid fields on submit, so no separate flag is needed to gate display.
    • isValid and canSubmit now mean "no validation error is currently displayed" rather than "the form would pass validation". Existing disabled={!isValid} bindings keep working under the new optimistic meaning.
    • computeEkycDisplayErrors and computeEkybDisplayErrors are no longer exported; errors live entirely on state.validationErrors.
  • Authentication: USER_IS_NOT_RECOGNIZED is retryable up to the configured capture-attempt limit (default 3) and then advances the flow, matching Web SDK 1.x, instead of ending the session on the first failure.
  • When face authentication fails with an advanceable terminal error (NONEXISTENT_CUSTOMER, HINT_NOT_PROVIDED), the orchestrator advances so the backend can route the customer to enrollment, rather than terminating.
  • A desktop-to-mobile handoff that finishes on mobile now completes the journey, instead of resuming the desktop session at the next module.
  • Government Validation shows a loading spinner while a check is still in progress, replacing the success check mark that appeared prematurely.
  • Manual capture is disabled when the Selfie or Authentication module runs with on-device face result submission enabled.
  • Analytics screen names were realigned across modules and new typed module tokens added. If you key logic off screen names in tracked events, re-check your mappings against Dashboard Events.
  • Consent and mandatory-consent copy is fetched in the active SDK language instead of always in English.
  • Core JavaScript is minified, reducing bundle size. See Bundle Optimization.
  • Default fonts are self-hosted with the package rather than fetched from a third-party CDN. See Third-Party Dependencies.

Fixed

  • ID Capture: expired-ID retry handling restored to 1.x parity; the back-of-ID prompt is skipped when the backend accepts a single-sided document even with alwaysCaptureBackOfId set; Continue buttons are labelled correctly on the front-ID success screen when no back scan is needed; the desktop preview is mirrored so on-screen movement matches the user; previewImageUrl is restored in the capture-only flow so the post-capture screen advances; the manual-capture tooltip no longer shifts the layout.
  • Manual ID upload: validation errors appear beneath the slot that failed instead of once at the bottom; uploaded slots survive switching between the ID and Passport tabs; images are normalized to JPEG before size validation; the quality-rejected error is no longer shown when the attempt was approved.
  • Digital ID upload: an excluded country or unaccepted document shows the failure screen instead of silently continuing.
  • Face Match: server-side face processing always runs before results are read; face match is skipped and the flow continues when the session was captured with extractIdFace: false; liveness snackbar labels are translated.
  • Selfie: the on-device selfie assets load reliably when a warm-up is already in flight.
  • Custom Watchlist calls the custom watchlist endpoint. The global Watchlist module is unchanged.
  • CURP Validation: the retry / manual-verify option is restored after a failed validation, and the verifying text is hidden while idle.
  • Geolocation: an unresolvable location renders localized copy instead of a literal "Unknown", and the desktop permission-denied screen is localized.
  • Electronic Signature: a session never associates more than one document; a signing error shows for three seconds and then finishes; error states route correctly by backend error type; a successful signQes response is treated as success; the signature canvas border renders on iOS 14.
  • Field Comparison submits names in the shape the dashboard expects, so they appear on the session.
  • Document Capture follows the camera-permission instructions before opening the camera, and PDFs render in an in-page viewer instead of a native embed that showed an OS-level "Open" button on iOS Safari and mobile Chromium.
  • Workflow and Flow: DYNAMIC_FORMS is registered and the flow advances when face-auth attempts are exhausted; the finish-status call is no longer issued on the desktop when the handoff completed on mobile; the active workflow node is used when fetching finish status, so hosts receive the completion redirect.
  • Redirect to Mobile: "Change phone number" works after an SMS resend hits the limit; a transient error no longer flashes on desktop right after the module loads.
  • The finish-process screen shown while the session result resolves no longer renders a title-less spinner.
  • Camera tracks are stopped explicitly at module transitions, and the rear camera is selected for back-camera capture on desktop and tablet devices.
  • Language selection from the home-screen settings modal survives a page reload.
  • A TypeError no longer appears in the console immediately after a flow completes.
  • Standalone @incodetech/web imports for redirect-to-mobile, cpf-ocr, document-capture, and field-comparison resolve correctly. See Individual Modules.
  • Street-level address selections are validated in eKYC and eKYB — choosing a city-level autocomplete result now reports that a street-level address is required.
  • Accessibility (WCAG 2.2 AA) fixes across capture, forms, and shared components: error messages are programmatically associated with their fields; processing and transition screens announce once instead of exposing fragmented text; dropdowns announce as select-only comboboxes with their required and invalid state; buttons keep an accessible name while loading; modals move initial focus to the dialog heading; scroll containers are keyboard-operable; placeholder text meets contrast minimums; and the camera-permission "requesting" screen no longer announces behind the native OS prompt.

Install: npm install @incodetech/web@2.1.0 @incodetech/core@2.1.0

2.0.1 — 2026-05-18

Fixed

  • Republished the 2.0.0 artifacts with their build output. Version 2.0.0 shipped without it and is deprecated on npm — install 2.0.1 or newer.
  • Digital ID upload: an excluded country or unaccepted document now shows the failure screen instead of silently continuing the flow; captureAttempts is honored exactly, rather than allowing one extra attempt; the terminal "no more attempts" screen is rendered and waits for the customer before returning to the document chooser; and the analyzing screen's status announcement is no longer visible on screen.

Install: npm install @incodetech/web@2.0.1 @incodetech/core@2.0.1

2.0.0 — 2026-05-15

Initial general availability of Web SDK 2.0 — a ground-up rewrite distributed as the @incodetech/core and @incodetech/web npm packages, replacing the 1.x @incodetech/welcome script bundle.

Added

Danger

Do not install 2.0.0. It was published without its build output and is deprecated on npm. Use

2.0.1 or newer.