Skip to content

iframe Embedding

Embed the Wedding Band Builder in an <iframe> for isolated, drop in integration. The viewer runs in its own context and you communicate with it via postMessage. Ideal for CMS platforms, Shopify stores, or any page where you can't add custom scripts.

Image

Screenshot showing a product page with the Wedding Band Builder embedded as an iframe, alongside the host page's own product description and Add to Cart button.

When to Use This

  • You're on a CMS or e-commerce platform (Shopify, WordPress, Squarespace, etc.)
  • You can't add custom <script> tags to the page
  • You want full isolation between the viewer and your page
  • You need cross-origin embedding

Quick Start

1. Host the Viewer Page

Create an HTML file that loads the mini-viewer inside the iframe. This page handles all the postMessage bridging automatically.

View full viewer page source and host this file on your server or CDN.

TIP

The viewer page reads ?manifest=, ?basePath=, and ?ui= from URL parameters, making it reusable across different product pages without code changes.

2. Embed on Your Page

html
<iframe
  id="wbb-iframe"
  src="https://your-site.com/wbb-viewer.html"
  style="width: 100%; height: 600px; border: none;"
  allow="camera; xr-spatial-tracking"
></iframe>

The allow attributes enable the AR try-on feature inside the iframe.

WARNING

Without allow="camera; xr-spatial-tracking" on the iframe, the AR button appears but fails silently when tapped. Always include these attributes:

html
<iframe src="viewer.html" allow="camera; xr-spatial-tracking"></iframe>

The page must also be served over HTTPS for camera access.

Image

Screenshot showing the iframe embedded in a simple page with the viewer filling the iframe area and the built-in panel visible.

3. Communicate via postMessage

javascript
const iframe = document.getElementById('wbb-iframe');
let requestId = 0;

// Send a command
function send(method, args = []) {
  iframe.contentWindow.postMessage({
    id: `req-${++requestId}`, method, args,
  }, '*');  // Use your specific origin in production
}

// Listen for events
window.addEventListener('message', (e) => {
  if (e.data?.event === 'ready') {
    send('setProfile', [0]);
    send('setMaterial', [1, 'Yellow', 'Polished']);
  }
  if (e.data?.event === 'price:updated') {
    document.getElementById('price').textContent =
      `$${e.data.data.pricing.totalUsd.toFixed(2)}`;
  }
});

View complete host page example for a full page with profile/material buttons and live price display.

Video

Video walkthrough showing the host page with the embedded iframe: clicking profile buttons changes the ring shape, clicking metal buttons changes the material, and the price updates in real time on the host page.

Headless Mode

Load the iframe with ?ui=false to hide the built-in panel and build all controls on the host page:

html
<iframe src="wbb-viewer.html?ui=false" style="width: 100%; height: 500px; border: none;"></iframe>

Use postMessage to query the catalog and control everything from your page. See Custom UI (Headless) for a full guide on building custom controls.

Image

Side-by-side: Left shows the iframe with the built-in panel. Right shows the iframe in headless mode with custom-styled controls on the host page.

postMessage Protocol

Sending commands (all API methods are available):

javascript
// Command:  { id: 'req-1', method: 'setWidth', args: [5.0] }
// Success:  { id: 'req-1', result: null }
// Error:    { id: 'req-1', error: { message: '...', source: 'api' } }

Receiving events (forwarded automatically from the viewer):

javascript
// { event: 'price:updated', data: { bandName: 'her', pricing: { totalUsd: 1250.00, ... } } }
Promise-based query helper
javascript
function query(method, args = []) {
  return new Promise((resolve, reject) => {
    const id = `req-${++requestId}`;
    const handler = (e) => {
      if (e.data?.id !== id) return;
      window.removeEventListener('message', handler);
      if (e.data.error) reject(new Error(e.data.error.message));
      else resolve(e.data.result);
    };
    window.addEventListener('message', handler);
    iframe.contentWindow.postMessage({ id, method, args }, '*');
  });
}

// Usage
const price = await query('getPrice', ['her']);
const snapshot = await query('getSnapshot');

E-Commerce Platform Examples

Ready-to-use integration examples for popular platforms. Each includes the iframe embed, live price display, and Add to Cart wiring.

PlatformWhat You GetExample
ShopifyLiquid section + cart integrationView example
WooCommerceShortcode + AJAX cart handlerView example
MagentoPHTML block + layout XML + controllerView example
BigCommerceStencil template + Storefront APIView example
WixHTML embed + Velo codeView example

Image

Screenshot of a product page with the Wedding Band Builder iframe embedded, showing the Add to Cart button with live price below the viewer.

Security: Restrict Origins

In production, always replace '*' with your specific domain:

javascript
// In the viewer page
window.parent.postMessage({ event: 'ready' }, 'https://your-store.com');

// In the host page
iframe.contentWindow.postMessage({ id, method, args }, 'https://your-cdn.com');
Responsive Sizing
css
.viewer-container {
  position: relative;
  width: 100%;
  padding-bottom: 75%; /* 4:3 aspect ratio */
}
.viewer-container iframe {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  border: none;
}
AR Support

The allow="camera; xr-spatial-tracking" attribute on the iframe enables AR try-on. Without it, the AR button will appear but fail silently.

Same-Origin Shortcut

If the iframe and host page are on the same origin, you can skip postMessage entirely:

javascript
const iframe = document.getElementById('wbb-iframe');
const viewer = iframe.contentWindow.ijewelViewer;
const api = viewer.getPluginByType('WeddingBandBuilder').controller;
api.setWidth(5.0);
URL Parameters

The viewer page accepts these query parameters:

ParameterDefaultDescription
manifestwedding-band-project.jsonURL to the manifest JSON file
basePath(viewer page directory)Base URL for resolving asset paths
uitrueSet to false to hide the built-in panel (headless mode)
html
<!-- Default: built-in UI shown -->
<iframe src="wbb-viewer.html"></iframe>

<!-- Headless: no built-in UI -->
<iframe src="wbb-viewer.html?ui=false"></iframe>

<!-- Custom manifest and base path -->
<iframe src="wbb-viewer.html?manifest=my-config.json&basePath=https://cdn.example.com/rings/"></iframe>

Next Steps