Skip to content

iframe Embedding

View the tested iframe host demo or browse its source.

The published source includes the host HTML, styles, and postMessage controller. Copy the complete iframe-demo folder so its relative asset URLs continue to resolve.

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.

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

Hosted iJewel3D Embed

Use the production Drive embed when you already have a published file. The fileId and instance come from the project you built in Create a Project:

html
<iframe
  id="wbb-iframe"
  src="https://ijewel3d.com/YOUR_INSTANCE/files/YOUR_FILE_ID/embedded?isAutoplay=true&showUiButtons=true"
  style="width: 100%; height: 600px; border: none;"
  allow="camera; xr-spatial-tracking"
></iframe>

The hosted route is:

text
https://ijewel3d.com/<instance>/files/<fileId>/embedded

Supported display parameters are case-sensitive:

ParameterEffect
isAutoplay=trueStart the viewer automatically
hideWbbUi=trueHide the built-in Wedding Band controls
showUiButtons=trueShow the viewer action buttons

The mini-viewer version inside a hosted iframe is controlled by the deployed iJewel3D application. The parent page cannot pin that internal version.

Viewer 0.6.11 or newer required for host controls

The cross-origin ready handshake and reliable teardown require Mini Viewer 0.6.11 or newer inside the hosted application. If the 3D rings render but the parent never receives ready, the embed deployment is older than the documented protocol. Upgrade the hosted application or use the self-hosted viewer page below, where you control the Viewer release.

Self-Hosted 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.

Embed the Self-Hosted 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.

Communicate via postMessage

javascript
const iframe = document.getElementById('wbb-iframe');
const viewerOrigin = new URL(iframe.src).origin;
let requestId = 0;

// Send a command
function send(method, args = []) {
  iframe.contentWindow.postMessage({
    id: `req-${++requestId}`, method, args,
  }, viewerOrigin);
}

// Listen for events
window.addEventListener('message', (e) => {
  if (e.source !== iframe.contentWindow) return;
  if (e.origin !== viewerOrigin) return;

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

Ready lifecycle

The Wedding Band plugin installs its global and postMessage exposure before it emits { event: 'ready', data: {} }. It emits ready exactly once for each successful project initialization. Wait for that event before sending commands or queries.

Importing another project or reloading the iframe starts a new lifecycle and produces a new ready event. Disposing or resetting the plugin removes its message listener and event forwarding, so an old controller cannot reply after teardown.

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

Headless Mode

For a self-hosted viewer page, 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>

For the hosted iJewel3D route, use hideWbbUi=true:

html
<iframe src="https://ijewel3d.com/YOUR_INSTANCE/files/YOUR_FILE_ID/embedded?hideWbbUi=true"></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.

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 timeout = setTimeout(() => {
      cleanup();
      reject(new Error(`Timed out waiting for ${method}`));
    }, 8000);

    const cleanup = () => {
      clearTimeout(timeout);
      window.removeEventListener('message', handler);
    };

    const handler = (e) => {
      if (e.source !== iframe.contentWindow) return;
      if (e.origin !== viewerOrigin) return;
      if (e.data?.id !== id) return;
      cleanup();
      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 }, viewerOrigin);
  });
}

// 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
Security: Restrict Origins

In production, always use the exact target origin and validate both the source window and origin of every incoming message:

javascript
const viewerOrigin = new URL(iframe.src).origin;
iframe.contentWindow.postMessage({ id, method, args }, viewerOrigin);

window.addEventListener('message', (event) => {
  if (event.source !== iframe.contentWindow) return;
  if (event.origin !== viewerOrigin) return;
  // Handle the validated message.
});
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.setWidthMultiplier(1.1);
URL Parameters

The self-hosted 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>
Hosted Embed URL Parameters

The iJewel3D hosted route uses isAutoplay, hideWbbUi, and showUiButtons. Parameter names are case-sensitive; for example, isAutoPlay is not equivalent to isAutoplay.

html
<iframe
  src="https://ijewel3d.com/YOUR_INSTANCE/files/YOUR_FILE_ID/embedded?isAutoplay=true&hideWbbUi=true&showUiButtons=true"
></iframe>

Next Steps