Migration Guide: WMS to WMEA
Table of Contents
Important resources:
- WMEA Developer Guide
- WMEA Sample App (open source) — includes a full React integration and a minimal plain JS / CDN version
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)
| Aspect | WMS (Hosted) | WMEA (Embedded) |
|---|---|---|
| Integration model | Redirect to external page | In-app JavaScript component |
| UI flow/navigation | Multi-page redirect/return | Single-page, embedded flow |
| Configuration | URL-based setup | Plain JS object |
| Results delivery | Callback/return URL or server webhook | In-app, real-time events |
| Error handling | After-return parsing | Real-time in-app handling |
| Telemetry/webhooks | Server-side webhooks | Client-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
debugModemakes 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 containercancel(reset)— cancels an active measurement; passtrueto also reset the SDKsetTheme('light' | 'dark')— switches the app themesetLanguage(language)— changes the display language at runtimesetAppSettings(token, refreshToken, studyId, measurementOptions?)— refreshes credentials without reinitializinggetLogs()— retrieves internal logs for debugging (seedebugModein 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, andon.eventhandlers before callinginit() - Configure new profile structure if you collect user demographics
- Optionally pass a custom
configobject
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.