Custom storefront
If you’re not on WooCommerce or BigCommerce, the integration is the same three pieces described in Storefront integration — you just wire them into whatever templating or rendering layer your storefront already uses.
1. Decide whether to render, server-side
Section titled “1. Decide whether to render, server-side”Wherever you generate a product page — a template render, a static build step, an API response your frontend consumes — check the product’s current state before deciding whether to include the try-on snippets at all:
curl https://api.integration.tryonvirtual.com/v1/products/TRYON_PRODUCT_UUID \ -H "Authorization: Bearer tryon_sk_your_key"TRYON_PRODUCT_UUID is the TryOn id — REST paths like this one always take that UUID, never
your own external_id (that works only in the storefront snippet’s productId and the
?external_id= filter — see Using your own IDs). If your sync
job only has its own identifier on hand, look the product up first with
GET /v1/products?external_id=... to get the id this call needs.
Render the button only when tryon_status == "active" and swap_ready == true. If you sync
TryOn state into your own database rather than calling the API per request (recommended for
anything higher-traffic than a handful of pages), keep both fields current there and branch on
your local copy instead — see Product lifecycle
for why both checks matter independently.
2. Template the two snippets with your own id
Section titled “2. Template the two snippets with your own id”Wire your product identifier — whichever value your system already has, ideally the same one
you’re using as external_id (see Using your own IDs) — into
both snippets:
<button type="button" data-tryon-product-id="{{ product.id }}">Try On</button>
<script async src="https://api.integration.tryonvirtual.com/api/v1/tryon/scripts/embed/bootstrap.js?shop_slug=YOUR_SHOP_SLUG&productId={{ product.id }}"></script>({{ product.id }} here is a stand-in for whatever your templating language uses — Jinja, ERB,
JSX, a plain string concatenation in a hand-rolled renderer. The two values that matter are your
shop slug and the product identifier.)
3. Handle client-side routing
Section titled “3. Handle client-side routing”The button-binding behavior described in Storefront integration
runs once, on DOMContentLoaded: the bootstrap script scans the page for elements carrying
data-tryon-product-id at that moment and binds them. That works fine for a traditional
multi-page site, where every product page is a fresh document load. It does not work for a
single-page app that swaps product views via client-side routing without a full page load — the
button rendered by your router after the initial load was never scanned, so it won’t be bound.
Two ways to handle this in a client-routed app:
- Trigger try-on from your own UI instead of relying on the auto-bound button. Skip
data-tryon-product-identirely and callwindow.openTryOn()from your route/component’s click handler once the bootstrap script for the current product has loaded. - Re-insert the script tag on every route change, so a fresh
<script>element (with the new product’sproductId) is added to the DOM each time the user navigates to a different product — this re-triggers the bind for the newly-rendered button.
Either way, make sure the render check from step 1 (tryon_status + swap_ready) runs again on
each client-side navigation too, not just on the initial page load — a SPA that fetches product
data once and caches it can otherwise show a stale button state after a merchant changes it.
API reference — full request/response schemas for every endpoint used across this guide.