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.

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>

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;
  }
});

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

  1. Confirm your listener filters by origin and source.
  2. Wait for ready before sending commands.
  3. Handle zone-selected and zone-confirmed separately when confirmModalOnClick=true.
  4. Keep a fallback path when zone metadata fields (region, side, aspect) are absent.
  5. 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:

  1. Store a local widgetReady flag.
  2. Flip it when type === 'ready'.
  3. 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:

  1. Validate event.origin against widget origin.
  2. Validate event.data.source === 'persoscan-widget'.
  3. Ignore everything else.

Expecting zone-confirmed without confirmation modal

Problem: zone-confirmed never appears.

Cause: confirmModalOnClick is disabled.

Solution:

  1. Enable confirmModalOnClick=true in URL config.
  2. Keep zone-selected handling in place for immediate click behavior.

Next Steps

Last updated: March 12, 2026