Clothing AI Try-On — SDK & Integration Guide
This guide covers all methods for embedding the WEARFITS Clothing AI Try-On experience into an e-commerce website or application: the JavaScript Modal SDK, direct iframe embedding, the PostMessage communication API, product data schemas, URL parameter integration, Shopify-specific setup, selection rules, and integration best practices.
See also: The latest hosted version of this guide is available at tryon.wearfits.com/docs/integration.
1. JavaScript Modal SDK (Recommended)
The JavaScript Modal SDK is the recommended integration path. It handles modal lifecycle, DOM mounting, and product synchronization automatically, with minimal code required on the host page.
Installation
<!-- Option A: Script tag -->
<script src="https://tryon.wearfits.com/sdk/wearfits.js"></script>
<!-- Option B: ES module import -->
<script type="module">
import { openWEARFITSTryOn } from 'https://tryon.wearfits.com/sdk/wearfits.esm.js';
</script>
Usage Example
const tryOn = new WearfitsTryOn({
apiKey: 'wf_prod_abc123...',
products: [
{
id: 'suit_01',
name: 'Executive Suit',
category: 'fullBody',
images: ['https://cdn.example.com/suit_front.jpg']
}
],
onComplete: (result) => {
console.log('Result image URL:', result.resultImageUrl);
},
onError: (error) => {
console.error('Try-on error:', error);
},
onClose: () => {
console.log('Modal closed');
}
});
tryOn.open();
Constructor Options
| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
string | null |
Your public WEARFITS API key. |
products |
array | [] |
Initial list of products to display in the try-on panel. |
baseUrl |
string | /api/v1 |
Proxy endpoint URL. Defaults to the application's built-in worker path. |
useMock |
boolean | false |
When true, uses mock data instead of live AI rendering. Useful for UI development and testing. |
onComplete |
function | null |
Callback invoked on successful try-on. Receives a fitting result object. |
onError |
function | null |
Callback invoked on system or AI errors. Receives an error object with code, message, and optional details. |
onClose |
function | null |
Callback invoked when the user closes the modal. |
2. Direct Iframe Integration
For integrations that require full control over the surrounding UI, the application can be embedded directly as an <iframe>.
Basic HTML Setup
<iframe
id="wearfits-frame"
src="https://tryon.wearfits.com"
allow="camera"
style="width: 100%; height: 100vh; border: none;"
></iframe>
The allow="camera" attribute is required for digital twin creation. Omitting it will prevent the camera from activating inside the iframe.
URL Parameters
Parameters are appended to the iframe src as standard query string values.
| Parameter | Description | Example |
|---|---|---|
products |
URL-encoded JSON array of product objects, or a URL pointing to a hosted JSON feed. | ?products=[{"id":"1",...}] |
productsUrl |
Legacy alias. URL to a public JSON file containing the product list. Use products with a URL value for new integrations. |
?productsUrl=https://cdn.example.com/catalog.json |
avatarId |
ID of an existing digital twin to load immediately, skipping twin creation. | ?avatarId=dt_abc123 |
step |
Start at a specific step: twin_creation or virtual_fitting. Intended for internal routing and debugging. |
?step=virtual_fitting |
3. PostMessage Communication API
When the application runs inside an iframe, the host page and the application exchange messages via window.postMessage. This enables dynamic product updates and handling of try-on outcomes without reloading the iframe.
Host → Application (Inbound Messages)
const iframe = document.getElementById('wearfits-frame');
// Send initialization after WEARFITS_READY is received
iframe.contentWindow.postMessage({
type: 'WEARFITS_INIT',
payload: {
products: [...],
apiKey: 'your-api-key',
baseUrl: 'https://api.wearfits.com'
}
}, 'https://tryon.wearfits.com'); // Use specific origin in production
| Message Type | Payload | Description |
|---|---|---|
WEARFITS_INIT |
{ products, apiKey, baseUrl } |
Full initialization of the application state. Send this in response to WEARFITS_READY. |
WEARFITS_SET_PRODUCTS |
[...products] |
Dynamically updates the garment list in the side panel without reinitializing the session. |
Application → Host (Outbound Events)
window.addEventListener('message', (event) => {
// Always validate the origin in production
if (event.origin !== 'https://tryon.wearfits.com') return;
const { type, payload } = event.data;
switch (type) {
case 'WEARFITS_READY':
// App has loaded — send WEARFITS_INIT now
initializeApp();
break;
case 'WEARFITS_COMPLETE':
console.log('Result image:', payload.resultImageUrl);
console.log('Selected products:', payload.selectedProducts);
break;
case 'WEARFITS_ERROR':
console.error('Error code:', payload.code, payload.message);
break;
case 'WEARFITS_CLOSE':
// Hide the iframe or overlay
document.getElementById('wearfits-modal').hidden = true;
break;
}
});
| Event Type | Payload | Description |
|---|---|---|
WEARFITS_READY |
{ version: "1.0.0" } |
Emitted when the application has fully loaded and is ready to receive WEARFITS_INIT. |
WEARFITS_COMPLETE |
{ resultImageUrl, selectedProducts, timestamp } |
Emitted on successful try-on. See Fitting Result Object. |
WEARFITS_ERROR |
{ message, code } |
Emitted on any system or AI failure. |
WEARFITS_CLOSE |
{} |
Emitted when the user requests to close the application. |
4. Product Data Schema
Product Object
All integration methods accept products in the same format.
{
"id": "top-001",
"name": "Classic White Blouse",
"category": "top",
"default": true,
"images": [
"https://cdn.example.com/products/blouse-model.jpg",
"https://cdn.example.com/products/blouse-flat.jpg"
]
}
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Unique product identifier. |
name |
string | Yes | Product display name shown in the selection panel. |
category |
string | Yes | Product category. See table below. |
images |
array | Yes | Array of 1–2 publicly accessible image URLs. |
default |
boolean | No | When true, the product is pre-selected when the application loads. |
Product Categories
| Category | Value | Typical Items |
|---|---|---|
| Tops | "top" |
T-shirts, blouses, shirts, sweaters, jackets |
| Bottoms | "bottom" |
Pants, skirts, shorts |
| Full Body | "fullBody" |
Dresses, jumpsuits, full outfits |
| Shoes | "shoes" |
All footwear |
Image Array Convention
The images array should contain 1–2 URLs:
images[0]— Primary (lifestyle or model) image. Used in the rendered try-on result preview.images[1]— Secondary (packshot or flat-lay) image. Used in the product selection carousel.
If only one image is supplied, it is used for both purposes.
Fitting Result Object
The WEARFITS_COMPLETE event and the onComplete SDK callback both receive the same result object:
{
"resultImageUrl": "https://api.wearfits.com/files/result_xyz.jpg",
"selectedProducts": [
{ "id": "top-001", "name": "Classic White Blouse", "category": "top" },
{ "id": "bottom-001", "name": "Navy Dress Pants", "category": "bottom" }
],
"timestamp": "2026-04-08T10:30:00Z"
}
5. Standalone Page (URL Parameters)
For the simplest possible integration — such as a "Try On" link that opens in a new tab — product data can be passed directly in the URL.
Encoded JSON
const products = [
{
id: 'top-001',
name: 'Classic White Blouse',
category: 'top',
default: true,
images: [
'https://cdn.example.com/products/blouse-model.jpg',
'https://cdn.example.com/products/blouse-flat.jpg'
]
}
];
const url = new URL('https://tryon.wearfits.com/');
url.searchParams.set('products', JSON.stringify(products));
window.open(url.toString(), '_blank');
Hosted JSON File
For larger catalogs where URL length is a concern, pass a URL to a hosted JSON file instead of inline data:
The application detects whether the products value is JSON or a URL automatically. The legacy productsUrl parameter is also accepted for backward compatibility.
Your server-hosted JSON should follow this structure:
{
"products": [
{
"id": "top-001",
"name": "Classic White Blouse",
"category": "top",
"default": true,
"images": ["https://cdn.example.com/products/blouse-model.jpg"]
}
]
}
6. Shopify Integration
The recommended approach for Shopify is to render the WEARFITS experience as an iframe modal on the product detail page (PDP), initialized via a Shopify app proxy feed.
Recommended Architecture
- WEARFITS iframe source:
https://tryon.wearfits.com - Product feed endpoint:
/apps/wearfits/products/{{ product.handle }}.json(served via Shopify app proxy) - Category mapping: Use a product metafield with namespace
wearfitsand keycategory; accepted values aretop,bottom,fullBody, andshoes
This approach keeps the customer on the PDP throughout the try-on experience, maintains a clear path back to add-to-cart, and avoids exposing API credentials in the browser.
App Proxy Setup (shopify.app.toml)
[access_scopes]
scopes = "write_app_proxy"
[app_proxy]
url = "/proxy/wearfits"
prefix = "apps"
subpath = "wearfits"
With this configuration:
https://{shop}.myshopify.com/apps/wearfits/products/{handle}.jsonproxies tohttps://{your-app}/proxy/wearfits/products/{handle}.json
Run shopify app dev after updating shopify.app.toml to apply the proxy config to your development store. Production stores require shopify app deploy. Choose proxy prefix and subpath values carefully: changes to these after stores are installed only apply to new installs.
Liquid Snippet — Try On Button (New-Tab Fallback)
Use this snippet on product pages to render a "Try On" button. The button is shown only for products that have a valid wearfits.category metafield, and opens the try-on experience in a new tab.
{%- assign wearfits_category = product.metafields.wearfits.category.value | default: product.metafields.wearfits.category -%}
{%- if wearfits_category != blank -%}
{%- capture wearfits_feed_url -%}
{{ shop.url }}/apps/wearfits/products/{{ product.handle }}.json
{%- endcapture -%}
<button
type="button"
id="wearfits-tryon-button-{{ product.id }}"
class="button button--secondary"
data-wearfits-url="https://tryon.wearfits.com/?products={{ wearfits_feed_url | strip | url_encode }}"
>
Try On
</button>
<script>
(() => {
const button = document.getElementById('wearfits-tryon-button-{{ product.id }}');
if (!button) return;
button.addEventListener('click', () => {
const url = button.getAttribute('data-wearfits-url');
if (!url) return;
window.open(url, '_blank', 'noopener,noreferrer');
});
})();
</script>
{%- endif -%}
PDP Modal with Iframe (Recommended)
For the full on-page experience, use an iframe modal initialized via PostMessage:
<button type="button" id="wearfits-open-iframe">Try On</button>
<div id="wearfits-modal" hidden>
<iframe
id="wearfits-frame"
src="https://tryon.wearfits.com"
allow="camera"
style="width: 100%; height: 100%; border: 0;"
></iframe>
</div>
const button = document.getElementById('wearfits-open-iframe');
const modal = document.getElementById('wearfits-modal');
const iframe = document.getElementById('wearfits-frame');
const feedUrl = `${window.Shopify.routes.root}apps/wearfits/products/{{ product.handle }}.json`;
button.addEventListener('click', () => {
modal.hidden = false;
});
window.addEventListener('message', async (event) => {
if (event.origin !== 'https://tryon.wearfits.com') return;
if (event.data?.type === 'WEARFITS_READY') {
const response = await fetch(feedUrl);
const payload = await response.json();
iframe.contentWindow.postMessage(
{ type: 'WEARFITS_INIT', payload },
'https://tryon.wearfits.com'
);
}
if (event.data?.type === 'WEARFITS_COMPLETE') {
console.log('Try-on result:', event.data.payload);
}
if (event.data?.type === 'WEARFITS_CLOSE') {
modal.hidden = true;
}
});
Shopify Field Mapping
| Shopify Field | WEARFITS Field |
|---|---|
product.id |
id |
product.title |
name |
product.metafields.wearfits.category |
category |
| Featured image + first alternate image | images |
| Current PDP product | default: true |
Feed Generation Rules
The app proxy endpoint should build its response using the following logic:
- Load the current product by handle.
- Read the
wearfits.categorymetafield. - Include the current product with
default: true. - Add compatible complementary products:
- If the current category is
top, add bottoms. - If the current category is
bottom, add tops. - If the current category is
fullBody, optionally add shoes. - If the current category is
shoes, add a complete top + bottom or fullBody look. - Limit the response to 2–4 products total.
- Return image URLs that are absolute, HTTPS, and publicly accessible.
7. Product Selection Rules
The try-on engine enforces the following garment combination rules:
- A Top + Bottom combination, or a single FullBody item, is required to generate a clothing try-on.
- Shoes are always optional and can be added to any outfit combination.
- Selecting a FullBody item automatically clears any Top or Bottom selections.
- Selecting a Top or Bottom automatically clears any FullBody selection.
These rules are enforced in the application UI; no additional handling is needed in the integration layer.
8. Best Practices
Image Quality
- Use product images of at least 500 × 500 px.
- Ensure consistent lighting and a white or neutral background.
- Include both a lifestyle (model) image and a packshot (flat-lay) where available —
images[0]should be the lifestyle shot. - Use HTTPS URLs for all images. Images must be publicly accessible; Data URLs are also supported.
Security
- Always validate
postMessageorigins in production — use the specific iframe origin rather than'*'. - Implement proper CORS headers on your image CDN to ensure images are accessible from the WEARFITS domain.
// Production-safe postMessage handler
window.addEventListener('message', (event) => {
if (event.origin !== 'https://tryon.wearfits.com') return;
// Process message...
});
Performance
- Trigger a background warmup call to
https://api.wearfits.com/health/warmupwhen the twin creation step first renders to reduce cold-start latency. - Trigger a second warmup call to
https://api.wearfits.com/health/queue-warmupwhen the garment selection step is displayed to pre-warm the fitting queue. - Consider lazy-loading the try-on iframe so it does not block the initial page render.
- Digital twin IDs are cached automatically in browser cookies and localStorage; avoid manually clearing them between sessions.
Camera Permissions
- Always include
allow="camera"on the<iframe>element. Without it, browsers block camera access regardless of user permission grants. - The application is fully responsive and optimized for mobile. Camera access is required for digital twin creation on all devices.
CORS and Persistence
- Ensure your
baseUrlproxy endpoint allows cross-origin requests from your host domain. - In iframe mode, verify that browser settings permit third-party cookies if you want the digital twin resume-session feature to work across visits.