Woman standing naturally while reading an open book

Developer docs

Virtual try-on integration & API documentation.

One iframe, one public key, one API for every widget — virtual try-on, 3D viewer, IPD, face shape, color analysis, and image tracking.

Quick start

Two commands: open and close. No action field — the key is the command. Replace public_key_********, your_sku_code, and your_model_id with values from your dashboard. Verify event.source. Results use type: makemetryon_result. Fit data uses type: makemetryon_* (see reference table).

1

Embed the iframe

Iframe src uses ?key=YOUR_PUBLIC_KEY. Add parent_origin only if the referrer is stripped.

index.html
<iframe
  id="makemetryon-iframe"
  src="https://widgets.makemetryon.com/?key=public_key_********"
  allow="camera; fullscreen"
  sandbox="allow-scripts allow-same-origin">
</iframe>
2

Wire up the parent page

Auth runs on open, not iframe load. Hot-swapping within the same widget skips a new metered session.

storefront.js
const iframe = document.getElementById('makemetryon-iframe')

iframe.addEventListener('load', () => {
  iframe.contentWindow.postMessage({ open: 'vto', sku: 'your_sku_code' }, '*')
})

window.addEventListener('message', (event) => {
  if (event.source !== iframe.contentWindow) return
  if (event.data?.close === true) modal.hidden = true
})

Reference

All postMessage payloads. Verify event.source and event.origin in production.

MessageDirectionNotes
{ open: 'vto', sku? }Parent → iframeCamera try-on. Catalog routes glasses, rings, earrings, watches, bracelets, and hats. Hot-swap by resending.
{ open: 'vto', model_id? }Parent → iframeSame catalog routing as sku.
{ open: '3d', model_id? }Parent → iframe3D viewer. Catalog picks the preset: jewelry, or glasses and hats.
{ open: 'ipd' }Parent → iframeIPD Measurement.
{ open: 'measurements-ipd-pro' }Parent → iframePupillary distance measurement with a card reference.
{ open: 'face-shape' }Parent → iframeFace Shape.
{ open: 'seasonal-color' }Parent → iframeSeasonal Colour Analysis.
{ open: 'image-target', sku? }Parent → iframeImage Target — sku is the album, not a catalog model.
{ open: 'image-target', model_id? }Parent → iframeImage Target — model_id is sent as the album id.
{ close: true }Parent → iframeTear down any widget.
{ close: true }iframe → ParentIPD, card PD, and Face Shape — shopper dismissed; hide your UI.
makemetryon_resultiframe → ParentSeasonal Colour — analysis finished; widget is seasonal_color.
makemetryon_resultiframe → ParentCard PD — widget is ipd and payload.method is card. Distances are millimetres.
makemetryon_get_fitiframe → ParentVTO Glasses — fit request.
makemetryon_fitParent → iframeVTO Glasses — fit response (3s timeout).
makemetryon_set_fitiframe → ParentVTO Glasses — save fit.
makemetryon_clear_fitiframe → ParentVTO Glasses — clear fit.

Examples

Replace your_sku_code and your_model_id with values from your dashboard.

open

Opens a widget or hot-swaps product/mode in place. Values: vto · 3d · ipd · measurements-ipd-pro · face-shape · seasonal-color · image-target. open: vto routes by catalog — glasses, jewelry/rings, jewelry/earrings, jewelry/watches, jewelry/bracelets, accessories/hats. Pass sku or model_id when needed — resend to change without a new session. For image-target the identifier resolves an image album, not a catalog model: model_id is sent as album_id.

storefront.js
const iframe = document.getElementById('makemetryon-iframe')
iframe.contentWindow.postMessage({ open: 'vto', sku: 'your_sku_code' }, '*')

iframe.contentWindow.postMessage({ open: '3d', sku: 'your_sku_code' }, '*')

iframe.contentWindow.postMessage({ open: 'vto', model_id: 'your_model_id' }, '*')

iframe.contentWindow.postMessage({ open: '3d', model_id: 'your_model_id' }, '*')

iframe.contentWindow.postMessage({ open: 'ipd' }, '*')

iframe.contentWindow.postMessage({ open: 'measurements-ipd-pro' }, '*')

iframe.contentWindow.postMessage({ open: 'face-shape' }, '*')

iframe.contentWindow.postMessage({ open: 'seasonal-color' }, '*')

iframe.contentWindow.postMessage({ open: 'image-target', sku: 'your_sku_code' }, '*')

close

Parent sends close to tear down. IPD, card PD, and Face Shape send close when the shopper dismisses the result — hide your modal only.

storefront.js
const iframe = document.getElementById('makemetryon-iframe')
iframe.contentWindow.postMessage({ close: true }, '*')
if (event.data?.close === true) modal.hidden = true

makemetryon_result

Fired when analysis succeeds. Switch on widget. Card PD reports widget ipd with payload.method card. Seasonal Colour sends four families and twelve seasons, both ranked highest first, as percentages. Show payload.top; keep the arrays for rankings.

storefront.js
window.addEventListener('message', (event) => {
  if (event.source !== iframe.contentWindow) return
  if (event.data?.type !== 'makemetryon_result') return

  if (event.data.widget === 'ipd' && event.data.payload?.method === 'card') {
    const { ipd, ipd_near, outer_face_width } = event.data.payload
    // Card ruler. Millimetres. ipd is distance PD; ipd_near is near PD.
  }

  if (event.data.widget === 'seasonal_color') {
    const { top, families, seasons } = event.data.payload
    // Headline: top.family.name — top.family.percentage
    // Season:   top.season.name — top.season.percentage
    // Rankings: families (4) and seasons (12), highest first
  }
})

Seasonal Colour payload

widget is seasonal_color. percentages are 0–100 (one decimal, each list sums to 100), not 0–1 probabilities.

result.json
{
  type: 'makemetryon_result',
  widget: 'seasonal_color',
  payload: {
    top: {
      family: { key: 'autumn', name: 'Autumn', percentage: 41 },
      season: { key: 'darkAutumn', name: 'Deep Autumn', family: 'Autumn', percentage: 18 },
    },
    families: [
      { key: 'autumn', name: 'Autumn', percentage: 41 },
      { key: 'winter', name: 'Winter', percentage: 27 },
      { key: 'summer', name: 'Summer', percentage: 19 },
      { key: 'spring', name: 'Spring', percentage: 13 },
    ],
    seasons: [
      { key: 'darkAutumn', name: 'Deep Autumn', family: 'Autumn', percentage: 18 },
      { key: 'trueAutumn', name: 'Warm Autumn', family: 'Autumn', percentage: 12 },
      { key: 'darkWinter', name: 'Deep Winter', family: 'Winter', percentage: 11 },
      { key: 'softAutumn', name: 'Soft Autumn', family: 'Autumn', percentage: 11 },
      { key: 'trueWinter', name: 'Cool Winter', family: 'Winter', percentage: 9 },
      { key: 'brightWinter', name: 'Bright Winter', family: 'Winter', percentage: 7 },
      { key: 'softSummer', name: 'Soft Summer', family: 'Summer', percentage: 7 },
      { key: 'trueSummer', name: 'Cool Summer', family: 'Summer', percentage: 6 },
      { key: 'lightSummer', name: 'Light Summer', family: 'Summer', percentage: 6 },
      { key: 'trueSpring', name: 'Warm Spring', family: 'Spring', percentage: 5 },
      { key: 'lightSpring', name: 'Light Spring', family: 'Spring', percentage: 4 },
      { key: 'brightSpring', name: 'Bright Spring', family: 'Spring', percentage: 4 },
    ],
  },
}

Card PD payload

Open with measurements-ipd-pro. widget stays ipd, the same name as the iris measurement. method is card. Distances are millimetres, rounded to 0.1. ipd is distance PD; ipd_near is near PD. outer_face_width matches the iris measurement.

result.json
{
  type: 'makemetryon_result',
  widget: 'ipd',
  payload: {
    ipd: 63.4,
    ipd_near: 61.2,
    face_width: 142.1,
    outer_face_width: 142.1,
    eye_width: 29.8,
    nose_bridge: 18.4,
    method: 'card',
    frames: 10,
    frames_ok: 3,
    adjusted: false
  }
}

makemetryon_get_fit

VTO Glasses requests stored fit data. Reply with makemetryon_fit within 3 seconds.

storefront.js
window.addEventListener('message', (event) => {
  if (event.source !== iframe.contentWindow) return
  if (event.data?.type === 'makemetryon_get_fit') {
    iframe.contentWindow.postMessage({ type: 'makemetryon_fit', payload: { ipd: 63, face_shape: 'oval' },
    }, '*')
  }
})

makemetryon_set_fit

Sent when the user's fit data changes. Save the received measurements in your database, local storage, or session.

storefront.js
window.addEventListener('message', (event) => {
  if (event.source !== iframe.contentWindow) return
  if (event.data?.type === 'makemetryon_set_fit') {
    const { payload, replace } = event.data
    // Save payload to your database, local storage, or session
    // If replace is true, replace the existing record instead of merging
  }
})

makemetryon_clear_fit

Sent when the user resets their measurements. Remove any stored fit data associated with the current user.

storefront.js
window.addEventListener('message', (event) => {
  if (event.source !== iframe.contentWindow) return
  if (event.data?.type === 'makemetryon_clear_fit') {
    // Remove stored fit data for the current user
  }
})