Quick Start
Embed the widget, listen for zone-selected events, and send commands back. A production-ready walkthrough with copy-paste code for any web application.
Use this page to complete a full first integration. You will embed the widget, receive events, send commands, and verify production behavior.
Prerequisites
- You can edit HTML and JavaScript in your application.
- You can run your app in a browser with developer tools.
- You have a license key if you need watermark-free production usage.
Without a license key, the widget still works and emits events. It displays a watermark.
1. Embed The Widget
Add the iframe to your page:
<iframe
id="persoscan-widget"
src="https://widget.persoscan.com?license=my-license-key"
width="800"
height="680"
allow="fullscreen"
style="border:none; color-scheme: light dark"
title="PersoScan Widget"
></iframe>Set the iframe origin correctly in your event checks. Compare against new URL(WIDGET_URL).origin, not a hardcoded wildcard.
2. Listen For Widget Events
Register one message listener and handle widget event types:
const WIDGET_ORIGIN = new URL('https://widget.persoscan.com').origin;
let widgetReady = false;
window.addEventListener('message', (event) => {
if (event.origin !== WIDGET_ORIGIN) return;
const msg = event.data;
if (!msg || msg.source !== 'persoscan-widget') return;
switch (msg.type) {
case 'ready':
widgetReady = true;
console.log('Widget is ready');
break;
case 'zone-selected':
console.log('Selected zone:', msg.data.zoneId, msg.data.zoneName);
break;
case 'zone-confirmed':
console.log('Confirmed zone:', msg.data.zoneId);
break;
case 'zone-cleared':
console.log('Selection cleared');
break;
case 'model-changed':
console.log('Model changed to:', msg.data.sex);
break;
case 'pain-submitted':
console.log('Pain submitted:', msg.data);
break;
case 'error':
console.error('Widget error:', msg.data.code, msg.data.message);
break;
}
});Keep one listener per page and route by msg.type. This avoids duplicate handlers in SPA screens.
3. Send Commands To The Widget
Use postMessage only after receiving the ready event:
const iframe = document.getElementById('persoscan-widget');
const WIDGET_ORIGIN = new URL('https://widget.persoscan.com').origin;
function sendWidgetCommand(type, data = {}) {
if (!widgetReady) {
console.warn('Wait for ready before sending commands.');
return;
}
iframe.contentWindow.postMessage({ type, data }, WIDGET_ORIGIN);
}
sendWidgetCommand('update-config', { theme: 'dark', lang: 'en' });
sendWidgetCommand('select-zone', { zoneId: 'lower-back' });
sendWidgetCommand('clear-selection', {});4. Production Checklist
- Confirm your listener filters by
originandsource. - Wait for
readybefore sending commands. - Handle
zone-selectedandzone-confirmedseparately whenconfirmModalOnClick=true. - Keep a fallback path when zone metadata fields (
region,side,aspect) are absent. - Test with and without a license feature that enables detailed zone metadata.
Common Mistakes
Commands sent before readiness
Problem: Commands have no effect.
Cause: You send postMessage before the widget emits ready.
Solution:
- Store a local
widgetReadyflag. - Flip it when
type === 'ready'. - Block command sends until the flag is
true.
Event listener receives unrelated messages
Problem: Your handler processes messages from other iframes.
Cause: The code checks only event.data.type.
Solution:
- Validate
event.originagainst widget origin. - Validate
event.data.source === 'persoscan-widget'. - Ignore everything else.
Expecting zone-confirmed without confirmation modal
Problem: zone-confirmed never appears.
Cause: confirmModalOnClick is disabled.
Solution:
- Enable
confirmModalOnClick=truein URL config. - Keep
zone-selectedhandling in place for immediate click behavior.
Next Steps
- Developer path:
- E-commerce path: