3D Jewelry Designer

The ring builder's JavaScript SDK

Load ring-builder.js from your 3JD address and call RMJRingBuilder.mount with your builder's slug. The SDK draws the builder in an iframe, sizes it to its content, and calls your functions when the shopper changes the ring, shares it or adds it to the cart. Return false from onAddToCart to write the cart line yourself, or let the SDK do it on Shopify.

3D Jewelry Designer3 min read

Mount a builder

Copy your builder's slug from Dashboard → Embeds, then:

<div id="ring"></div>
<script src="https://3djewelrydesigner.com/ring-builder.js"></script>
<script>
  var builder = RMJRingBuilder.mount("#ring", {
    slug: "YOUR_EMBED_SLUG",
    onSelection: function (s) { showPrice(s.priceCents, s.currency); },
    onAddToCart: function (s, instruction, meta) { /* see below */ },
  });
</script>

Without any JavaScript of your own, a container works too. The SDK finds it when the page loads:

<div data-rmj-ring-builder data-rmj-slug="YOUR_EMBED_SLUG" data-rmj-height="640px"></div>
<script src="https://3djewelrydesigner.com/ring-builder.js"></script>

The data attributes are data-rmj-slug, data-rmj-base, data-rmj-height, data-rmj-min-height, data-rmj-max-height, data-rmj-fit and data-rmj-datalayer.

Options

OptionWhat it does
slugYour builder's slug. Required.
baseUrlThe 3JD address to load from. Defaults to the address the script came from.
heightThe starting height: a number of pixels, any CSS length, "auto", or { mobile, tablet, desktop }.
minHeight, maxHeightLimits on the height the builder asks for.
autoResizetrue or false to force resizing on or off. Left out, the builder decides from its own layout setting.
fit"viewport" keeps a frame you sized to the screen as it is.
autoCartfalse stops the SDK writing the cart line, so only your onAddToCart runs.
loading"eager" or "lazy". Left out, a builder near the top of the page loads at once and one far below waits until it is close.
borderRadius, titleThe frame's corner radius and its accessible title.
resumeA shared-design token. Left out, the SDK reads ?c= from your page's address, so a shared link opens the shared ring.
dataLayertrue, or the name of your own array: each builder event is also pushed to the page's dataLayer, for Google Tag Manager.

Callbacks

  • onReady(): the builder has loaded.
  • onSelection(selection): every change the shopper makes.
  • onAddToCart(selection, instruction, meta): the shopper pressed the cart button. meta holds quoteToken, properties (the line-item properties), sku, priceCents and currency. Return false to stop the SDK from writing the cart itself.
  • onShare(selection, url): the shopper shared the ring; url reopens it.
  • onEnquiry(selection): on a builder set to Send an enquiry, the shopper sent the form. The enquiry is already in your Leads.
  • onResize(height, data): the frame changed height.
  • onAdded(instruction) and onError(error): after the SDK wrote a Shopify cart line, or failed to.

The selection

{
  "band": "classic-round",
  "shape": "Round",
  "setting": "cp",
  "carat": 1,
  "metal": "yellow_gold_14k",
  "variant": null,
  "engraving": { "text": "Always", "font": "serif", "position": "inside" },
  "sku": "RB-RND-100-14Y",
  "priceCents": 248000,
  "currency": "USD"
}

shape, setting and carat are the values in your own catalogue, and gem is there when the builder offers a gem choice. sku and priceCents come from our server, not from the shopper's browser (price is an older display figure: use priceCents). On add to cart the selection also has quoteId, the lead saved for that add. engraving is null when there is none.

Writing the cart yourself

On Shopify the SDK writes the cart line for you: it finds or makes the right variant and adds it, then sends the shopper to the cart or checkout if your builder is set to. With the builder's own checkout (hosted) or a Shopify draft order (draft) it opens that page. Otherwise instruction.mode is "event" and the add is yours to make. Use meta.sku and meta.priceCents, and put meta.properties on the line so the order can be traced back to the builder.

If your server sets the line price, check it first: send meta.quoteToken to POST /api/public/ring-builder/verify as { "token": "…" }. The answer is { "valid": true, "sku", "priceCents", "currency", "expiresAt" } for a genuine quote, and { "valid": false } for a changed or expired one. No API key is needed: the token is the proof.

Google Tag Manager

With dataLayer: true the SDK pushes the builder's events to window.dataLayer (or to the array you name), so your own analytics can count them. Each push has event and rmj_embed (the builder's slug):

EventWhenAlso has
rmj_readyThe builder has loaded.
rmj_selectionThe shopper changed the ring.rmj_sku, rmj_value, rmj_currency, rmj_shape, rmj_metal
rmj_add_to_cartThe shopper pressed the cart button.the same
rmj_shareThe shopper shared the ring.the same
rmj_enquiryThe shopper sent an enquiry (a builder set to Send an enquiry).the same
rmj_try_onThe shopper opened try-on.

rmj_value is the price in whole units: 2480 where the selection's priceCents is 248000. The names start with rmj_ so they never double your store's own events: map them to your tags in Tag Manager. Nothing is pushed unless you turn this on.

The handle

mount returns an object with:

  • iframe: the frame element.
  • remeasure(): ask the builder to report its height again, for example after a tab or an accordion around it opens.
  • destroy(): remove the frame and every listener the SDK added.

RMJRingBuilder.version is the script's version.

Media Only embeds

A Media Only embed (a 360° hero and captured stills, no cart) mounts with RMJRingBuilder.mountMedia("#media", { slug, fallback }), or with <div data-rmj-media data-rmj-slug="…">. fallback is a selector for your own product gallery: it is hidden while the 3D view loads and shown again if the view cannot run. columns sets the number of still tiles in a row, and onFail(reason) tells you when the fallback was used.

Listening without the SDK

A plain <iframe> of the builder sends the same events with window.postMessage. Each message has source: "rmj-ring-builder" and a type: ready, selection, addToCart, share, resize, tryon-open or tryon-close. Check event.origin is your 3JD address before you use one.

Related

  • How an integration fits together

    From a shopper building a ring to the order in your systems: what runs where, which price to trust, and how products and 3D models stay in step.

  • Webhooks: events, payloads and signatures

    Send leads, saved designs, carts and orders to your CRM or backend as signed webhooks, and check each delivery with a few lines of code.

  • Band engraving on a ring

    Let shoppers engrave a message on the band: live curved 3D text in nine fonts, with symbols, placement, size and an optional surcharge.

Put your own design in the studio

Upload a file and see it rendered photoreal, ready to try on and to embed.