Migration Guide: WMS to WMEA

Table of Contents

Important resources:

Overview

This guide covers migration from the hosted Web Measurement Service (WMS) to the Web Measurement Embedded App (WMEA). If you're looking for a complete guide to WMEA itself (not migration), please refer to the WMEA Developer Guide.

While the integration model changes, the fundamentals remain the same: users complete a measurement and structured results are returned. WMEA embeds that experience directly in your app and simplifies setup, error handling, and result delivery, as detailed in the sections below.

Quick Comparison (WMS vs WMEA)

AspectWMS (Hosted)WMEA (Embedded)
Integration modelRedirect to external pageIn-app JavaScript component
UI flow/navigationMulti-page redirect/returnSingle-page, embedded flow
ConfigurationURL-based setupPlain JS object
Results deliveryCallback/return URL or server webhookIn-app, real-time events
Error handlingAfter-return parsingReal-time in-app handling
Telemetry/webhooksServer-side webhooksClient-side app events

Core Architectural Changes

WMS: Hosted Service Architecture

  • Users redirected to web measurement service
  • Complex URL-based configuration and encrypted profile data
  • Results delivered via callback URLs after user returns
  • Required server-side infrastructure for encryption/decryption

WMEA: Embedded Component Architecture

  • Complete measurement experience within your application
  • Direct JavaScript component integration
  • Real-time event-based results and error handling
  • Simplified client-side configuration objects
  • No external redirections or page transitions

Key Benefits of Migration

High-impact benefits:

  • Lower costs by eliminating dependency on Visage
  • Faster load and runtime performance
  • Users stay on your URL
  • Version control: test new WMEA versions before adopting them or enable auto-upgrades; unlike WMS, you're not forced onto a single global version

Simplified Development:

  • Direct JavaScript integration eliminates URL construction
  • Event-driven architecture replaces callback parsing
  • Reduced server-side infrastructure requirements, including no longer needing to configure CNAMEs
  • debugMode makes it significantly easier to debug integration issues compared to WMS

Enhanced Control & Customization:

  • Full control over your navigation bar on the measurement page; in WMS your branding was constrained
  • Customized error handling and user feedback on measurement page

This migration transforms a service-oriented architecture into a component-oriented one, providing better user experience, development simplicity, and integration flexibility while maintaining all core biometric measurement capabilities.

Measurement

Initialization

The biggest change: WMS's multi-step redirect + URL/encryption flow becomes a single init() call in WMEA.

Initialize the embedded app on your measurement page by creating a MeasurementEmbeddedApp instance and calling init() with a MeasurementEmbeddedAppOptions object:

import MeasurementEmbeddedApp from '@nuralogix.ai/web-measurement-embedded-app';

const measurementApp = new MeasurementEmbeddedApp();

await measurementApp.init({
  container,      // HTMLDivElement to mount the app into
  appPath,        // Path to WMEA static assets
  settings: {
    token,
    refreshToken,
    studyId,
  },
  profile,
  language,       // optional
  apiUrl,         // optional, for region-specific data processing
  config,         // optional
});

Note that on.results, on.error, and on.event handlers should be set up before calling init(). See the Integration Details chapter of the WMEA Developer Guide for complete setup examples.

After init() resolves, you also have access to:

  • destroy() — unmounts the app and cleans up the container
  • cancel(reset) — cancels an active measurement; pass true to also reset the SDK
  • setTheme('light' | 'dark') — switches the app theme
  • setLanguage(language) — changes the display language at runtime
  • setAppSettings(token, refreshToken, studyId, measurementOptions?) — refreshes credentials without reinitializing
  • getLogs() — retrieves internal logs for debugging (see debugMode in Config)

Migration Checklist

Remove WMS Components:

  • URL construction and encryption logic
  • URL/redirect-based configuration management
  • Profile data encryption/decryption
  • Session ID generation and callback handling
  • Server-side webhook infrastructure

Implement WMEA Components:

  • Install WMEA npm package (@nuralogix.ai/web-measurement-embedded-app)
  • Create a new route (e.g., /measurement) to init and host the embedded app (recommended)
  • Set up on.results, on.error, and on.event handlers before calling init()
  • Configure new profile structure if you collect user demographics
  • Optionally pass a custom config object

The open source sample app is a useful reference throughout this process — it includes a full React integration and a minimal plain JS / CDN version.

This change eliminates the complex initialization workflow while providing better error handling and real-time integration.

Configuration

Brief WMS recap: Configuration lived behind redirects with URL-managed parameters and included many presentation and transport fields.

WMEA simplification: Configuration is now a small plain JavaScript object passed directly to init(). Many WMS fields are obsolete and removed.

Configuration at a glance (all fields optional — sensible defaults are applied if omitted):

type Config = {
  checkConstraints?: boolean;      // default: true
  cameraFacingMode?: 'user' | 'environment'; // default: undefined
  defaultCameraId?: string;        // default: undefined
  cameraAutoStart?: boolean;       // default: false
  measurementAutoStart?: boolean;  // default: false
  cancelWhenLowSNR?: boolean;      // default: true
  debugMode?: boolean;             // default: false
  downloadPayloads?: boolean;      // default: false
};

For camera selection, cameraFacingMode lets the browser pick a device by facing direction ('user'/'environment'), while defaultCameraId selects a specific deviceId — useful for persisting a user's camera choice across sessions (e.g. the standard front camera over the ultra-wide on iPad). cameraFacingMode takes precedence when both are set; leave it unset to select by defaultCameraId or the browser default.

debugMode enables verbose console logging and is especially useful during integration. downloadPayloads saves binary payload files per measurement chunk for sharing with NuraLogix support. See the Integration Details chapter for full descriptions of each option.

Profile

In WMS, profile details were passed via URL parameters. In WMEA, pass a typed profile object directly to init(). Fields must use the faceAttributeValue enum values exported from the package.

import { faceAttributeValue } from '@nuralogix.ai/web-measurement-embedded-app';

const { SEX_ASSIGNED_MALE_AT_BIRTH, SMOKER_FALSE, BLOOD_PRESSURE_MEDICATION_FALSE, DIABETES_NONE } =
  faceAttributeValue;

const profile: Profile = {
  age: 40,
  heightCm: 180,
  weightKg: 60,
  sex: SEX_ASSIGNED_MALE_AT_BIRTH,
  smoking: SMOKER_FALSE,
  bloodPressureMedication: BLOOD_PRESSURE_MEDICATION_FALSE,
  diabetes: DIABETES_NONE,
  bypassProfile: false,
};

You can also bypass demographic collection by setting bypassProfile: true.

See the Profile type and faceAttributeValue enum in the WMEA Developer Guide for the full set of accepted values.

Results

WMS delivered results via redirect callback URLs; WMEA delivers them directly via the on.results handler set before init():

measurementApp.on.results = (results) => {
  store.setResults(results);
  router.push('/results');
};

Results are available immediately upon measurement completion. See the Integration Details chapter for result shapes, grouping, and metadata.

Error Handling

Handle errors in real time via on.error:

import { ErrorCodes } from '@nuralogix.ai/web-measurement-embedded-app';

measurementApp.on.error = (error) => {
  switch (error.code) {
    case ErrorCodes.MEASUREMENT_PREPARE_FAILED:
      // Invalid or expired credentials
      break;
    case ErrorCodes.CAMERA_PERMISSION_DENIED:
      // Guide user to allow camera access
      break;
    default:
      console.error('Measurement error', error);
  }
};

You have full control over presentation and logic: log errors and optionally display your own modal or toast with your brand styles and copy.

The WMEA sample app includes default messaging and handling for all error scenarios that you can copy and adapt. For the full ErrorCodes reference, see the Integration Details chapter of the WMEA Developer Guide.

App Events

WMS delivered telemetry via server-side webhooks. In WMEA, the same visibility is provided client-side through app events, giving you real-time insight into the measurement lifecycle without server infrastructure. Events cover the full lifecycle — camera permission, asset loading, measurement start/completion, constraint violations, intermediate results, and more.

Each event includes an event key, level (INFO / WARN / ERROR), timestamp, and a typed payload:

import { appEvents } from '@nuralogix.ai/web-measurement-embedded-app';

measurementApp.on.event = (appEvent) => {
  switch (appEvent.event) {
    case appEvents.MEASUREMENT_STARTED.event:
      console.log('Measurement started', appEvent.payload.measurementId);
      break;
    case appEvents.FACE_TRACKER_LOADED.event:
      console.log('SDK version', appEvent.payload.version);
      break;
    // ...
  }
};

One naming change from WMS to be aware of: SCAN_COMPLETED has been renamed to MEASUREMENT_COMPLETED. Also, if an error occurs before a measurementId is created, measurementId will be an empty string rather than undefined.

For the full appEvents reference and payload shapes, see the Integration Details chapter of the WMEA Developer Guide.

Conclusion

Refer to the WMEA Developer Guide for more details. We have tried to make migrating as simple as possible and provide extensive documentation in getting setup with the new architecture. Please contact support if you encounter problems.