Configura Studio docs

Three ways to embed a 3D product customizer on your site. Pick the one that matches your stack. All three load from the same hosted widget — no build step, no SDK to manage, no dependencies beyond a single script tag.

Quick start

The fastest way to put a live 3D customizer on any page. Replace your-product-slug with the slug from your product's URL in the Configura dashboard.

<script src="https://configurastudio.com/configura-widget.js"></script>
<configura-customizer product="your-product-slug"></configura-customizer>

That's it. The customizer renders inline where you place it, at 700px tall by default. Buyers can rotate, pick colors, add text, and save their configuration — you receive the print-ready file on every order.

Where's my product slug? In the Configura dashboard, open any product. The slug is the URL segment after /customize/ — for example mountain-key-holder-mnz1mgbc.

Choose an integration

Configura ships three embed paths. They all talk to the same backend and render the same viewer — they differ in how much JavaScript your host page needs.

1 Custom element

One HTML tag. Works anywhere web components are supported (which is everywhere modern).

BEST FOR: most sites
2 Script API

Call ConfiguraWidget.init() from JavaScript. Gives you programmatic control, callbacks, and a returned instance.

BEST FOR: dynamic mounts, SPAs
3 Raw iframe

A plain <iframe>. No JavaScript. Works in restrictive platforms, email-like CMSes.

BEST FOR: locked-down embeds
Custom elementScript APIIframe
Requires JS in host pageYes (one script)YesNo
Lines of HTML251
Event listenersDOM eventsCallbackspostMessage
Programmatic destroyDOM removal.destroy()DOM removal
Works in React/VueNativevia refNative

Order flow: code vs cart

However the customizer is embedded, the buyer eventually needs to communicate their selection back to your store. Configura supports two flows for this. They're not exclusive — you can run code-based on one product and cart on another — but each customizer is configured for one flow at a time.

A Code-based

Buyer customizes, gets a 6-character code, pastes it into your store's existing fields (Etsy Personalization, cart notes, order properties). You match the code to the saved selection in the Order Manager.

BEST FOR: Etsy, link snippets, low-volume sellers
B Merchant embed (cart)

Buyer customizes, clicks Add to Cart inside the embed, the embed posts sku and priceCents to your storefront via postMessage. Your storefront creates the line item directly.

BEST FOR: Shopify, BigCommerce, custom storefronts
Code-basedMerchant embed
Buyer action to orderPaste code into a fieldClick Add to Cart
Host page integrationNone (uses existing fields)postMessage listener required
Etsy compatibleYes (the only Etsy path)No (Etsy blocks iframes)
Shopify compatibleYes (via cart note)Yes (preferred)
Order Manager requiredYes (match code to order)No (cart has selection inline)
Merchant registration requiredNoYes

Merchant embed (cart-enabled)

The merchant embed wires the customizer's Add to Cart button directly into your storefront. It's the right choice for Shopify, BigCommerce, or any custom storefront where you control the product page's JavaScript. Setup involves two pieces: registering your storefront as a merchant in the Configura dashboard, and listening for the cart-add message on your host page.

1. Register your storefront as a merchant

In the dashboard, go to Integrations → Merchants and add your store's URL. The origin you register here is the only one allowed to trigger cart actions — Configura validates the parent origin via postMessage before sending cart events. If the origin isn't registered, the embed still loads and buyers can customize, but the Add to Cart button won't appear.

2. Embed with cart enabled

Add cart="1" on the custom element (or ?cart=1 on the iframe URL). The Add to Cart button mounts inside the embed once the merchant origin handshake completes.

<configura-customizer
  product="mountain-key-holder"
  cart="1"
  sku="MKH-001"
  price="2999"
  product-name="Mountain Key Holder"
></configura-customizer>

price is in cents (integer). The example above is $29.99. sku and price are the values the embed will post back when the buyer clicks Add to Cart — see SKU & price below for resolution rules.

3. Listen for the cart message on your host page

When the buyer clicks Add to Cart, the embed posts a message to window.parent. Your storefront page listens and adds the line item:

// In your Shopify theme (e.g. main-product.liquid <script>)
window.addEventListener('message', function(e) {
  // Only trust messages from configurastudio.com
  if (e.origin !== 'https://configurastudio.com') return;
  // Configura embeds tag every message with this source string
  if (e.data?.source !== 'configura-embed') return;
  if (e.data.type !== 'add-to-cart') return;

  const { product, meta } = e.data.data;

  // Shopify: add line item via the Ajax Cart API
  fetch('/cart/add.js', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      id: /* your variant id, looked up by product.sku */,
      quantity: 1,
      properties: { 'Configura code': meta.configuraCode }
    })
  }).then(() => { window.location = '/cart'; });
});

Cart message payload

The full message envelope is:

{
  source: 'configura-embed',
  version: /* protocol version, e.g. "2" */,
  type: 'add-to-cart',
  data: {
    product:  { slug, name, sku, priceCents },
    config:   { /* full buyer selections — regions, colors, text */ },
    preview:  { image, mimeType } | null,
    meta:     { embedUrl, timestamp, merchantId, configuraCode, configHash }
  }
}
FieldTypeDescription
data.product.slugstringConfigura product slug
data.product.namestringResolved display name (override wins)
data.product.skustringResolved SKU (mapping wins, then URL param)
data.product.priceCentsintegerResolved price in cents
data.configobjectBuyer's selections — regions, colors, text. Mirrors the v1 state shape.
data.previewobject | nullSnapshot of the customizer viewport — image (data URL), mimeType. null if capture failed.
data.meta.embedUrlstringThe full URL the embed was loaded from
data.meta.timestampISO stringWhen the buyer clicked Add to Cart
data.meta.merchantIdstring | nullThe merchant ID Configura validated against
data.meta.configuraCodestring6-character order code (e.g. ABC123). Surface this in your line item so sellers can locate the matching order in Configura admin.
data.meta.configHashstring | null12-hex stable hash of the selection — useful for cart-line dedup. null on browsers without SubtleCrypto.
Verify e.origin AND e.data.source. Always check that incoming messages come from https://configurastudio.com AND that e.data.source === 'configura-embed' before acting on them. Other scripts on the page may post messages with overlapping type values; the source string disambiguates.

Using the Script API instead

If you're using ConfiguraWidget.init() rather than the custom element, pass an onAddToCart callback. The widget unwraps the envelope for you — you get just the data object:

ConfiguraWidget.init({
  container: '#configurator',
  product: 'mountain-key-holder',
  cart: true,
  sku: 'MKH-001',
  price: 2999,
  onAddToCart: function(data) {
    // data === e.data.data from the postMessage envelope
    // (product, config, preview, meta — same shape as above)
    console.log('Add to cart:', data.product, data.meta.configuraCode);
  }
});

Custom element users can also use the DOM event API: el.addEventListener('configura-add-to-cart', e => { /* e.detail === data */ }).

SKU & price resolution

When the buyer clicks Add to Cart, the embed needs to know which SKU and price to send. Values are resolved in priority order:

#SourceWhen it's used
1Merchant product mapping (dashboard)Wins if a mapping exists for this customizer on this merchant
2URL params: ?sku=...&price=...Used when no merchant mapping is set
3Custom element attributes: sku, priceSame as URL params — the element forwards them as URL params on the underlying iframe

For most setups, leaving the merchant mapping blank and putting SKU and price directly on the embed is fine — the snippet generator at Add to Your Store does this automatically. Use a merchant mapping only when you need to override the embed values for a specific merchant (e.g. a different price on a partner's Shopify than on your own).

Etsy ignores SKU and price. Etsy uses the code-based flow exclusively, so any SKU/price you set on an Etsy customizer is ignored. The 6-character code is the only thing that matters there.

<configura-customizer>

A standards-compliant custom element. Drop the script once per page; use the tag anywhere in HTML, JSX, Vue templates, or Svelte components.

<script src="https://configurastudio.com/configura-widget.js"></script>

<configura-customizer
  product="mountain-key-holder"
  height="620px"
  accent="#2a1525"
  brand="Nord Haus"
></configura-customizer>

The script can be loaded once in <head> and reused across multiple customizer tags on the same page.

Attributes

AttributeTypeDefaultDescription
product * string Product slug. Required.
height string 700px CSS height. Accepts 620px, 80vh, or bare 620 (px assumed).
accent hex color #3b82f6 Primary button color inside the viewer.
brand string Shop name shown in the customizer's header.
hide-branding boolean false Hide "Powered by Configura" watermark. Requires Enterprise plan.
hide-header boolean false Hide the customizer's own top bar (product title + Save button).
Runtime attribute changes are not observed. If you need to swap products, remove the element and re-create it. Attribute observation is intentionally omitted to keep the v1 implementation predictable.

Events

The element dispatches standard DOM CustomEvents that bubble. Listen with addEventListener.

EventFires whenevent.detail
configura-ready Customizer has loaded and is interactive Initial state object
configura-order-saved Buyer clicks Save Selection Selection object with regions, text, and configuration code
configura-resize Customizer's content height changes { height: number }
const el = document.querySelector('configura-customizer');

el.addEventListener('configura-order-saved', (e) => {
  // e.detail.code is the 7-char customization code
  // shown to the buyer and tied to the order
  console.log('Buyer saved configuration:', e.detail.code);
});

ConfiguraWidget.init()

The script API is the lower-level surface the custom element is built on top of. Use it when you need a reference to the instance (for later .destroy() or .getState() calls), or when you're mounting the customizer dynamically in response to some user action.

<div id="my-customizer"></div>
<script src="https://configurastudio.com/configura-widget.js"></script>
<script>
  const widget = ConfiguraWidget.init({
    container: '#my-customizer',
    product: 'mountain-key-holder',
    height: '620px',
    accent: '#2a1525',
    onReady: (data) => console.log('ready', data),
    onOrderSaved: (data) => console.log('saved', data),
  });
</script>

Options

OptionTypeDescription
container *string | HTMLElementCSS selector or DOM node to mount into.
product *stringProduct slug.
heightstringCSS height. Default 700px.
widthstringCSS width. Default 100%.
accentstringHex color for primary buttons.
brandstringShop name shown in header.
hideBrandingbooleanHide watermark (Enterprise plan).
hideHeaderbooleanHide customizer's top bar.
onReadyfunctionCalled once the customizer is interactive.
onOrderSavedfunctionCalled when buyer saves their configuration.
onResizefunctionCalled when content height changes.

Instance methods

The return value of ConfiguraWidget.init() is an instance with these methods:

MethodDescription
widget.getState(callback) Asks the customizer for its current selection. callback receives {regions: [...], ...}.
widget.destroy() Removes the iframe, detaches event listeners, cleans up state. Call before unmounting in SPAs.
Destroying all instances at once: ConfiguraWidget.destroyAll() iterates every live widget on the page and destroys each. Useful during route changes.

Iframe embed

If your host platform blocks external JavaScript — or you just want the simplest possible integration — embed the customizer as a raw iframe. No widget script required.

<iframe
  src="https://configurastudio.com/embed.html?product=mountain-key-holder"
  width="100%"
  height="700"
  frameborder="0"
  allow="accelerometer; autoplay; gyroscope"
></iframe>

URL parameters

ParameterValuesDescription
product *slugRequired product identifier.
embedtrueEnables embed mode (hides certain nav elements).
hideBranding1Hide Configura watermark. Enterprise only.
hideHeadertrueHide product title bar.
accenthexURL-encoded hex color — e.g. %232a1525.
brandstringURL-encoded shop name.
Cross-origin events: Because the iframe is served from a different origin than your site, you'll need postMessage to receive order-save events. The other two methods handle this for you.

Etsy

Etsy doesn't allow JavaScript, iframes, or custom HTML inside listings. Instead of embedding, Configura injects a link to your customizer into the listing description — buyers click through, configure, and come back with a 6-character code they paste into a listing message or variation.

This is set up from the Configura dashboard's integration flow, not docs — connect your Etsy shop, pick a listing, and Configura writes the link in for you.

Available on all plans. Etsy integration doesn't require Enterprise — the watermark is kept, and the redirect includes your Configura branding.

Shopify

Shopify works with either order flow. Pick based on how integrated you want the cart experience to feel.

Option A — Code-based (simplest)

Embed the customizer with the custom-element snippet. The buyer customizes, gets a 6-character code, and pastes it into the cart-note or order-properties field at checkout. No JavaScript on your end.

<!-- In sections/main-product.liquid (or your product template) -->

<script src="https://configurastudio.com/configura-widget.js"></script>
<configura-customizer
  product="{{ product.metafields.configura.slug }}"
  height="620px"
></configura-customizer>

Store the Configura product slug in a product metafield (configura.slug) so each Shopify product maps to its matching customizer.

Option B — Merchant embed (cart-enabled)

Add cart="1" plus a SKU and price. When the buyer clicks Add to Cart inside the embed, your theme's listener creates a Shopify line item directly. See the full merchant embed section for the message payload and a complete listener example.

<configura-customizer
  product="{{ product.metafields.configura.slug }}"
  cart="1"
  sku="{{ product.selected_variant.sku }}"
  price="{{ product.selected_variant.price }}"
  product-name="{{ product.title | escape }}"
></configura-customizer>

Then register your Shopify store as a merchant in Integrations → Merchants so the cart message is trusted. The merchant embed section has the matching theme-side JS that listens for the cart message and POSTs to Shopify's /cart/add.js.

Enterprise plan required. Shopify embedding uses white-label branding (your shop name, your accent color, no Configura watermark) and is gated to Enterprise.

Squarespace

Add the customizer via a Code Block. Squarespace sanitizes some inline scripts — the safest path is the raw iframe method:

<iframe
  src="https://configurastudio.com/embed.html?product=your-slug"
  width="100%"
  height="620"
  frameborder="0"
></iframe>

For a white-label experience (custom accent, no watermark) you'll need Enterprise — add &hideBranding=1&accent=%232a1525&brand=Your%20Shop to the src URL.

WordPress & WooCommerce

Drop the custom-element snippet into any page's Custom HTML block, or paste it into your theme's single-product.php template to add it to every product page. WooCommerce buyers can save a customization code as an order note — pair with a plugin that exposes note fields on the cart if you want it captured automatically.

<!-- WordPress Custom HTML block -->
<script src="https://configurastudio.com/configura-widget.js"></script>
<configura-customizer product="your-slug"></configura-customizer>

For a fully integrated cart experience, WooCommerce can also use the merchant embed (cart-enabled) flow — add cart="1", register your store in Integrations → Merchants, and listen for the configura:addToCart postMessage in your theme. The handler typically calls WooCommerce's AJAX endpoint ?wc-ajax=add_to_cart to create the line item.

React & Next.js

The custom element works natively in React — no wrapper required. Load the script once (e.g. in your <Head> or app.tsx), then use the tag like any other JSX element:

// In your app layout, once:
import Script from 'next/script';
<Script src="https://configurastudio.com/configura-widget.js" strategy="afterInteractive" />

// In any component:
export function ProductPage({ slug }) {
  const ref = useRef();

  useEffect(() => {
    const el = ref.current;
    const handler = (e) => console.log('saved', e.detail);
    el?.addEventListener('configura-order-saved', handler);
    return () => el?.removeEventListener('configura-order-saved', handler);
  }, []);

  return <configura-customizer ref={ref} product={slug} height="620px" />;
}
TypeScript: declare the custom element in a .d.ts file so JSX accepts it:
declare namespace JSX {
  interface IntrinsicElements {
    'configura-customizer': {
      product: string;
      height?: string;
      accent?: string;
      brand?: string;
      'hide-branding'?: boolean;
      ref?: any;
    };
  }
}

When your component unmounts (route change, conditional render), the element's disconnectedCallback runs automatically and destroys the underlying widget. No leaks.

Styling & theming

The customizer renders inside an iframe, so you cannot reach INTO it with CSS from your host page. What you can control:

  • Outer size: set height on the element. Width stretches to fit the container.
  • Accent color: accent="#..." changes primary buttons inside the viewer.
  • Shop name: brand="Nord Haus" shows in the header.
  • Chrome hiding: hide-branding and hide-header for a fuller white-label look.
  • Wrap in a card: the element is just a block element — wrap it in a div with your own border, padding, or glassmorphism styling.

For deeper customization (custom fonts, full layout changes, translated UI), reach out about a custom embed build.

Troubleshooting

The customizer doesn't load

  • Check the browser console for errors. [Configura] Missing required "product" option means your slug is empty.
  • Verify your product is published. Draft products won't render.
  • Confirm the slug matches exactly — slugs are case-sensitive.

The iframe loads but the model doesn't show

  • Likely a CORS or CDN issue with the STL file. Check your browser's Network tab for failed requests.
  • Very large STLs (>25MB) may time out on slow connections. Re-export at a lower resolution.

I can't rotate the 3D model

  • Rotation requires pointer events to reach the iframe. Make sure no parent element has pointer-events: none.
  • On mobile, the customizer captures touches by design (so rotation feels natural). Scroll past it by touching outside the customizer.

My saved camera view isn't showing

  • Hard-refresh your browser (⌘⇧R / Ctrl+F5) to bust the cache.
  • If the view only updated in the customizer but not in the embed, redeploy — the embed uses the latest published product config.

My custom element isn't rendering

  • Ensure configura-widget.js loaded before the element needs to upgrade. The order doesn't matter (custom elements upgrade on registration), but the script must load at some point.
  • Check that the browser supports custom elements — essentially all browsers from 2019 onward do.

Browser support

Configura's customizer uses WebGL via Three.js. It runs on:

  • Chrome / Edge 90+
  • Firefox 90+
  • Safari 14+ (desktop & iOS)
  • Samsung Internet 14+

Roughly 98% of global web traffic. The embed gracefully degrades with a "WebGL not supported" message on the fractional cases that can't run it — buyers aren't blocked from checkout, they just can't preview in 3D.

Content Security Policy

If your host site has a strict CSP, whitelist these sources:

DirectiveValue
script-srchttps://configurastudio.com
frame-srchttps://configurastudio.com
connect-srchttps://configurastudio.com https://*.supabase.co

Ready to ship your first customizer?

Set up a working 3D product page in under 10 minutes. No credit card required.