Developer Documentation

PrimeStyle VTO API

Add AI-powered virtual try-on to any e-commerce experience. One API call turns a product photo into a try-on result.

~15s

Avg. response

99.9%

Uptime

1 line

SDK install

Introduction

PrimeStyle Virtual Try-On lets shoppers see themselves wearing any product — directly on your website. Our AI generates photorealistic results in 15-20 seconds, plus AI-powered size recommendations. Three ways to integrate:

REST API

Full control. Virtual try-on, AI sizing, and size guide extraction endpoints. Build your own UI, handle the flow however you want.

React SDK

Ship in minutes. Drop-in React component with try-on and sizing built in. Auto-extracts product images — no backend work needed.

Shopify App

No code required. Install from the Shopify App Store and get try-on + AI sizing on all product pages automatically.

How it works — API Mode

1Customer uploads their photo
2You send photo + garment image(s)
3Get try-on result via SSE or polling

How it works — SDK / Shopify App

1App auto-detects product on page
2Customer tries on & gets size recommendation
3Result appears in the modal

Sizing API endpoints

In addition to virtual try-on, the API includes AI-powered sizing:

POST /v1/sizing/sizeguideExtract size chart from product data
POST /v1/sizing/recommendGet AI size recommendation from measurements

Quick Start

Get your first virtual try-on result in under 5 minutes.

1

Get your API key

Sign up at myaifitting.com and grab your API key from the Developer Dashboard.

2

Submit a try-on request

Send the customer's photo as modelImage and the product image as garmentImage. The API returns immediately with a jobId while processing happens in the background.

curl -X POST https://myaifitting.com/api/v1/tryon \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"modelImage": "https://example.com/customer-photo.jpg",
"garmentImage": "https://your-store.com/products/blue-shirt.jpg"
}'
3

Get the result

Option A — SSE stream (recommended): Open an SSE connection and listen for vto-update events. You get the result instantly when it's ready.

SSE Stream (recommended)
// Recommended: Use SSE instead of polling (faster)
const eventSource = new EventSource(
"https://myaifitting.com/api/v1/tryon/stream?key=YOUR_API_KEY"
);
eventSource.addEventListener("vto-update", (e) => {
const data = JSON.parse(e.data);
if (data.jobId === myJobId) {
if (data.status === "completed") {
console.log("Result:", data.imageUrl);
eventSource.close();
}
if (data.status === "failed") {
console.error("Error:", data.error);
eventSource.close();
}
}
});

Option B — Polling: If you can't use SSE, poll the status endpoint every 2 seconds until status is "completed".

Polling (fallback)
// Poll for result
let result;
while (true) {
const res = await fetch(
`https://myaifitting.com/api/v1/tryon/status/${jobId}`,
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
result = await res.json();
if (result.status === "completed") {
console.log("Result image:", result.imageUrl);
break;
}
if (result.status === "failed") {
console.error("Failed:", result.message);
break;
}
// Wait 3 seconds before polling again
await new Promise(r => setTimeout(r, 3000));
}

Completed Status Response

json
{
"jobId": "67b3a1f2e4b0c8d9a1234567",
"status": "completed",
"imageUrl": "https://res.cloudinary.com/.../result/abc123.png",
"message": "Completed"
}

Authentication

Every API request must be authenticated. Include your API key in the Authorization header as a Bearer credential.

API Keys

Get your API key from the Developer Dashboard. Your key is scoped to your account and controls billing.

HTTP Header
Authorization: Bearer YOUR_API_KEY

Important: Never expose your API key in client-side code. Always call the API from your server. For client-side integration, use the Drop-in SDK which handles authentication securely.

Try-On Balance

Each successful virtual try-on counts as one try-on from your account balance. If you don't have enough try-ons remaining, the API returns a 402 with your current balance. Failed try-ons are not counted.

402 Response
// 402 Insufficient balance response
{
"error": "INSUFFICIENT_BALANCE",
"message": "Not enough try-ons remaining. Balance: 0",
"required": 1,
"currentBalance": 0
}

API Reference

Base URL: https://myaifitting.com/api

All endpoints require authentication. The try-on API is asynchronous — you submit a job and receive the result image via SSE stream or polling. We do not store your customer photos or garment images — only the generated result is returned.

Create Try-On Job

POST/v1/tryonAuth required

Submit a virtual try-on job. Send the customer's photo and a garment image — that's it. Returns immediately with a jobId (202 Accepted). Processing takes 15-20 seconds in the background. Use SSE or polling to get the result.

Request Body

NameTypeDescription
modelImagestringURL or base64 data URI of the customer's photo.
garmentImagestringURL or base64 data URI of the garment/product image.

Example Request

curl -X POST https://myaifitting.com/api/v1/tryon \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"modelImage": "https://example.com/customer-photo.jpg",
"garmentImage": "https://your-store.com/products/blue-shirt.jpg"
}'

Response 202

json
{
"jobId": "67b3a1f2e4b0c8d9a1234567",
"status": "processing",
"tryOnsUsed": 1,
"newBalance": 49
}

Get Try-On Status

GET/v1/tryon/status/:jobIdAuth required

Check the status of a try-on job. Poll this endpoint every 3 seconds until status is 'completed' or 'failed'. For real-time results, use the SSE stream instead (recommended).

Path Parameters

NameTypeDescription
jobIdstringThe job ID returned from POST /v1/tryon

Example Request

curl https://myaifitting.com/api/v1/tryon/status/67b3a1f2e4b0c8d9a1234567 \
-H "Authorization: Bearer YOUR_API_KEY"

Response 200

json
// While processing:
{
"jobId": "67b3a1f2e4b0c8d9a1234567",
"status": "processing",
"imageUrl": null,
"message": "Processing..."
}
// When completed:
{
"jobId": "67b3a1f2e4b0c8d9a1234567",
"status": "completed",
"imageUrl": "https://res.cloudinary.com/.../result/abc123.png",
"message": "Completed"
}
// On failure (the try-on is not counted):
{
"jobId": "67b3a1f2e4b0c8d9a1234567",
"status": "failed",
"imageUrl": null,
"message": "Failed: Safety filter blocked the image"
}

Real-time Stream (SSE)

GET/v1/tryon/stream?key=YOUR_API_KEYAuth required

Open a persistent SSE connection to receive real-time try-on results. This is the recommended way to get results — faster than polling and you get the result image the instant it's ready. Pass your API key as a query parameter since EventSource can't set headers.

Example Request

// Open SSE connection (pass key as query param)
const eventSource = new EventSource(
"https://myaifitting.com/api/v1/tryon/stream?key=YOUR_API_KEY"
);
// Listen for try-on results
eventSource.addEventListener("vto-update", (e) => {
const data = JSON.parse(e.data);
const { jobId, status, imageUrl, error } = data;
if (status === "completed") {
// Display the result image
showResultImage(imageUrl);
eventSource.close();
}
if (status === "failed") {
showError(error);
// Failed try-ons are not counted
eventSource.close();
}
});
eventSource.onerror = () => eventSource.close();

Response 200

json
// SSE event format:
event: vto-update
data: {"jobId":"67b3a1...","status":"completed","imageUrl":"data:image/png;base64,...","error":null,"timestamp":1740067200000}

Privacy: We do not store your customer photos or garment images. Images are processed in memory and only the generated result is returned. Failed try-ons are not counted against your balance.

Upload Image

POST/v1/tryon/uploadAuth required

Upload a customer photo and get back a hosted URL. Use this if you need to convert a file upload into a URL before calling the try-on endpoint. Max file size: 50MB.

Example Request

const formData = new FormData();
formData.append("file", customerPhotoFile);
const res = await fetch("https://myaifitting.com/api/v1/tryon/upload", {
method: "POST",
headers: { "Authorization": "Bearer YOUR_API_KEY" },
body: formData,
});
const { url } = await res.json();
// Use this URL as modelImage in your try-on request

Response 200

json
{
"url": "https://res.cloudinary.com/.../tryon-uploads/abc123.jpg"
}

AI Size Recommendation

POST/v1/sizing/recommendAuth required

Get an AI-powered size recommendation for a customer. Send the customer's body measurements (or height/weight for a quick estimate) along with product details and an optional size guide. Returns the recommended size, confidence level, international size conversions, and detailed measurement match analysis.

Request Body

NameTypeDescription
method"exact" | "quick"Use "exact" for body measurements, "quick" for height/weight estimate.
measurementsobjectRequired when method is "exact". Customer body measurements in cm.
measurements.gender"male" | "female" | "unisex"Customer gender for sizing context.
measurements.chestnumberChest circumference in cm.
measurements.bustnumberBust circumference in cm.
measurements.waistnumberWaist circumference in cm.
measurements.hipsnumberHip circumference in cm.
measurements.shoulderWidthnumberShoulder width in cm.
measurements.sleeveLengthnumberSleeve length in cm.
measurements.inseamnumberInseam length in cm.
measurements.footLengthCmnumberFoot length in cm (for shoes).
quickEstimateobjectRequired when method is "quick".
quickEstimate.heightCmnumberHeight in cm (100-250).
quickEstimate.weightKgnumberWeight in kg (30-300).
quickEstimate.gender"male" | "female" | "unisex"Customer gender.
productobjectProduct details for sizing context.
product.titlestringProduct title.
product.vendorstringBrand name.
product.productTypestringProduct type (e.g. "T-Shirt", "Jeans").
product.variantsarrayAvailable product variants with size info.
sizeGuideobjectSize guide data (from /v1/sizing/sizeguide or your own). Dramatically improves accuracy.
sizeGuide.headersstring[]Column headers, e.g. ["Size", "Chest (cm)", "Waist (cm)"].
sizeGuide.rowsstring[][]Row data matching headers, e.g. [["M", "94-100", "78-84"]].
localestringCustomer region code (e.g. "US", "EU") to prioritize sizing format.

Example Request

curl -X POST https://myaifitting.com/api/v1/sizing/recommend \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"method": "exact",
"measurements": {
"gender": "male",
"chest": 104,
"waist": 84,
"hips": 96,
"shoulderWidth": 46
},
"product": {
"title": "Classic Fit Oxford Shirt",
"vendor": "Brand Name",
"productType": "Shirt",
"variants": [
{ "title": "S", "option1": "S" },
{ "title": "M", "option1": "M" },
{ "title": "L", "option1": "L" },
{ "title": "XL", "option1": "XL" }
]
},
"sizeGuide": {
"headers": ["Size", "Chest (cm)", "Waist (cm)", "Hips (cm)"],
"rows": [
["S", "88-94", "76-82", "90-96"],
["M", "94-100", "82-88", "96-102"],
["L", "100-106", "88-94", "102-108"],
["XL", "106-112", "94-100", "108-114"]
]
},
"locale": "US"
}'

Response 200

json
{
"recommendedSize": "L",
"recommendedLength": null,
"confidence": "high",
"reasoning": "Your chest of 104cm falls within the L range of 100-106cm in the size guide. Waist of 84cm fits the M range (82-88cm) but L (88-94cm) provides a comfortable fit overall.",
"internationalSizes": {
"US": "L",
"UK": "L"
},
"matchDetails": [
{ "measurement": "Chest", "userValue": "104 cm", "chartRange": "100-106 cm", "fit": "good" },
{ "measurement": "Waist", "userValue": "84 cm", "chartRange": "88-94 cm", "fit": "loose" },
{ "measurement": "Hips", "userValue": "96 cm", "chartRange": "102-108 cm", "fit": "tight" },
{ "measurement": "Shoulders", "userValue": "46 cm", "chartRange": "44-47 cm", "fit": "good" }
]
}

Pro tip: Pass a sizeGuide for dramatically better results. Use the /v1/sizing/sizeguide endpoint below to auto-extract it from a product page, or provide your own structured size chart data.

Which measurements should I send?

Men'sTops / Shirts / Jackets

Chest
104cm
measurements.chest
Waist
84cm
measurements.waist
Shoulder Width
46cm
measurements.shoulderWidth
Sleeve Length
65cm
measurements.sleeveLength
Neck
40cm
measurements.neckCircumference
{
  "method": "exact",
  "measurements": {
    "gender": "male",
    "chest": 104,
    "waist": 84,
    "shoulderWidth": 46,
    "sleeveLength": 65,
    "neckCircumference": 40
  },
  "product": {
    "title": "Your Product Name",
    "variants": [
      {
        "title": "S"
      },
      {
        "title": "M"
      },
      {
        "title": "L"
      }
    ]
  }
}
Request body

Extract Size Guide

POST/v1/sizing/sizeguideAuth required

AI-powered size guide extraction. Send product details (description, metafields, images) and the AI extracts the size chart if one exists. Supports size charts in HTML tables, plain text, images (vision), metafields, and third-party size guide apps. Returns structured data you can pass directly to /v1/sizing/recommend.

Request Body

NameTypeDescription
productobjectProduct details to search for size chart data.
product.titlestringProduct title.
product.descriptionstringProduct description HTML — often contains size charts in tables.
product.vendorstringBrand name.
product.productTypestringProduct type.
product.variantsarrayProduct variants (helps identify available sizes).
product.optionsarrayProduct options (e.g. Size, Color).
product.metafieldsarrayProduct metafields — may contain size chart data or references.
domHtmlstringHTML extracted from the product page DOM (e.g. from a third-party size guide modal).
domImagesstring[]Image URLs found in size guide modals/sections on the page.
sizeGuideRawanyRaw size guide data in any format (JSON, HTML, text). The AI parses it into structured format.

Example Request

curl -X POST https://myaifitting.com/api/v1/sizing/sizeguide \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"product": {
"title": "Classic Fit Oxford Shirt",
"vendor": "Brand Name",
"description": "<table><tr><th>Size</th><th>Chest</th></tr><tr><td>M</td><td>94-100cm</td></tr></table>"
}
}'

Response 200

json
// Size guide found:
{
"found": true,
"title": "Size Guide",
"headers": ["Size", "Chest (cm)", "Waist (cm)", "Hips (cm)"],
"rows": [
["S", "86-91", "71-76", "86-91"],
["M", "91-97", "76-81", "91-97"],
["L", "97-102", "81-86", "97-102"],
["XL", "102-107", "86-91", "102-107"]
],
"source": "extracted"
}
// No size guide found:
{
"found": false
}

Flexible input. You can pass size guide data in any format — HTML tables in the product description, JSON from metafields, raw text, or even images of size charts. The AI extracts and structures it for you. Pass the result directly as the sizeGuide field in /v1/sizing/recommend.

Error Codes

All errors return a JSON object with a message and a code field:

Error Response
{
"error": "INSUFFICIENT_BALANCE",
"message": "Not enough try-ons remaining. Balance: 0",
"required": 1,
"currentBalance": 0
}
CodeHTTPDescription
UNAUTHORIZED401Missing or invalid API key
MODEL_IMAGE_REQUIRED400No model (customer) image provided
GARMENT_IMAGE_REQUIRED400No garment image provided
INSUFFICIENT_BALANCE402Not enough try-ons remaining. Response includes required and currentBalance
JOB_NOT_FOUND404Job ID does not exist or doesn't belong to your account
VALIDATION_ERROR400Request body failed validation (invalid URL format, etc.)
PROCESSING_FAILED500Internal error during generation. Failed try-ons are not counted

Failed try-ons are free: If a try-on job fails during generation, it is not counted against your balance. You are only charged for successful try-ons.

React SDK

Add virtual try-on to your React / Next.js app with a single component. No API key props, no backend work — just install, set an env variable, and use the component:

  • API key from env — reads NEXT_PUBLIC_PRIMESTYLE_API_KEY automatically
  • Typed props — full TypeScript support with typed callbacks
  • Fully customizable — style with Tailwind classes, CSS, or buttonStyles / modalStyles props
  • Handles photo upload, compression, loading states, SSE streaming, and result display

Installation

1. Install the package

bash
npm install @primestyleai/tryon

2. Add your API key to .env.local

.env.local
NEXT_PUBLIC_PRIMESTYLE_API_KEY=ps_live_your_key_here

Get your key from the Developer Dashboard.

3. Use the component

Your product page
import { PrimeStyleTryon } from '@primestyleai/tryon/react';
function ProductPage({ product }) {
return (
<div>
<h1>{product.name}</h1>
<PrimeStyleTryon
productImage={product.image}
buttonText="Try It On"
onComplete={(result) => {
console.log('Result:', result.imageUrl);
}}
/>
</div>
);
}

Component & Props

PrimeStyleTryon Props

NameTypeDescription
productImagestringURL of the garment/product image to try on. Recommended — pass this explicitly for best results. If omitted, the SDK auto-detects the main product image on the page (via og:image, Schema.org JSON-LD, or common selectors like .product-image).
buttonTextstringText on the trigger button (default: "Virtual Try-On")
apiUrlstringCustom API URL. Defaults to NEXT_PUBLIC_PRIMESTYLE_API_URL env or production
showPoweredBybooleanShow "Powered by PrimeStyle AI" in modal footer (default: true)
showIconbooleanShow the default camera icon in the trigger button (default: true). Set to false to hide it.
buttonIconReact.ReactNodeCustom icon element to replace the default camera icon. Pass any React node (e.g. an <svg> or <img>).
buttonStylesButtonStylesCustomize button appearance (see Customization below)
modalStylesModalStylesCustomize modal appearance (see Customization below)
classNamesPrimeStyleClassNamesOverride element classes with Tailwind or custom CSS (see Customization below)
classNamestringAdditional CSS class on the root wrapper
styleCSSPropertiesInline styles on the root wrapper
onOpen() => voidCalled when modal opens
onClose() => voidCalled when modal closes
onUpload(file: File) => voidCalled when user uploads a photo
onProcessing(jobId: string) => voidCalled when try-on generation starts
onComplete(result) => voidCalled when result is ready. result: { jobId, imageUrl }
onError(error) => voidCalled on error. error: { message, code? }
sizeGuideDataRecord<string, Record<string, string>>Size guide data keyed by size. e.g. { "M": { chest: "94cm", waist: "78cm" } }. Enables AI size recommendations in the modal.
localestringBCP-47 locale tag for UI translations (e.g. "en", "ja", "pt-BR"). Auto-detects from browser if omitted. Supports 20 languages: English, Spanish, French, German, Italian, Swedish, Japanese, Czech, Danish, Dutch, Norwegian, Polish, Portuguese (BR & PT), Finnish, Turkish, Thai, Chinese (Simplified & Traditional), and Korean.

No API key prop needed. The component reads NEXT_PUBLIC_PRIMESTYLE_API_KEY from your environment automatically.

Pass productImage explicitly. While the SDK can auto-detect the product image from your page (using og:image, Schema.org JSON-LD, or common CSS selectors), we recommend passing the productImage prop directly for the most reliable results.

Customization

Button Styles

Pass a buttonStyles object to customize the trigger button:

javascript
<PrimeStyleTryon
productImage={product.image}
buttonStyles={{
backgroundColor: '#000000',
textColor: '#ffffff',
borderRadius: '50px',
padding: '16px 32px',
fontSize: '16px',
fontWeight: '700',
width: '100%',
border: '2px solid #333',
hoverBackgroundColor: '#222',
iconSize: '20px',
iconColor: '#fff',
boxShadow: '0 4px 12px rgba(0,0,0,0.3)',
}}
/>

Modal Styles

Pass a modalStyles object to customize the try-on modal:

javascript
<PrimeStyleTryon
productImage={product.image}
modalStyles={{
backgroundColor: '#ffffff',
textColor: '#111111',
overlayColor: 'rgba(0,0,0,0.7)',
borderRadius: '16px',
maxWidth: '520px',
fontFamily: '"Inter", sans-serif',
headerBackgroundColor: '#f5f5f5',
headerTextColor: '#111111',
closeButtonColor: '#666',
uploadBorderColor: '#dddddd',
uploadBackgroundColor: '#fafafa',
primaryButtonBackgroundColor: '#000000',
primaryButtonTextColor: '#ffffff',
primaryButtonBorderRadius: '50px',
loaderColor: '#000000',
resultBorderRadius: '16px',
}}
/>
ButtonStylesModalStyles
backgroundColoroverlayColor
textColorbackgroundColor
borderRadiustextColor
fontSizeborderRadius / width / maxWidth
fontFamily / fontWeightfontFamily
paddingheaderBackgroundColor / headerTextColor
bordercloseButtonColor
width / heightuploadBorderColor / uploadBackgroundColor
hoverBackgroundColor / hoverTextColoruploadTextColor / uploadIconColor
iconSize / iconColorprimaryButtonBackgroundColor / TextColor
boxShadowloaderColor / resultBorderRadius

Button Icon

The trigger button shows a camera icon by default. You can hide it, or replace it with your own icon:

javascript
{/* Hide the icon text only */}
<PrimeStyleTryon
productImage={product.image}
showIcon={false}
buttonText="Try It On"
/>
{/* Custom icon */}
<PrimeStyleTryon
productImage={product.image}
buttonIcon={<img src="/my-icon.svg" alt="" style={{ width: 20, height: 20 }} />}
/>
{/* Custom SVG icon */}
<PrimeStyleTryon
productImage={product.image}
buttonIcon={
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 0 0 0-7.78z" />
</svg>
}
/>

Tailwind CSS / Custom Classes

Use the classNames prop to style any element with Tailwind utilities or your own CSS classes. Classes are appended to the default ps-tryon-* classes:

javascript
<PrimeStyleTryon
productImage={product.image}
classNames={{
button: "bg-black text-white rounded-full px-8 py-4 hover:bg-gray-800",
modal: "bg-white rounded-2xl shadow-2xl",
header: "bg-gray-50 border-b border-gray-200",
title: "text-gray-900 text-lg",
submitButton: "bg-blue-600 text-white rounded-lg hover:bg-blue-700",
uploadZone: "border-dashed border-gray-300 rounded-xl p-10",
downloadButton: "bg-green-600 text-white rounded-lg",
retryButton: "bg-gray-100 text-gray-700 border border-gray-300",
}}
/>

Available classNames keys:

KeyElement
rootRoot wrapper
buttonTrigger button
overlayModal backdrop
modalModal container
headerModal header
titleModal title
closeButtonClose button
bodyModal body
uploadZoneUpload drop zone
uploadText / uploadHintUpload text & hint
submitButtonSubmit & retry button
spinnerLoading spinner
downloadButton / retryButtonResult action buttons
error / errorTextError container & text
poweredByFooter attribution

Normal CSS

All elements use ps-tryon-* class names that you can target directly in your stylesheet:

your-styles.css
/* Override the trigger button */
.ps-tryon-btn {
background: #000;
color: #fff;
border-radius: 50px;
padding: 16px 32px;
}
/* Override the modal */
.ps-tryon-modal {
background: #fff;
color: #111;
}
/* Override the submit button */
.ps-tryon-submit {
background: #2563eb;
color: #fff;
}

All three approaches can be combined. Priority: Tailwind/classNames > CSS variables (buttonStyles/modalStyles) > default styles.

Callbacks

Use typed callback props for analytics, custom behavior, or integration with your app:

javascript
<PrimeStyleTryon
productImage={product.image}
onOpen={() => {
analytics.track('tryon_opened');
}}
onUpload={(file) => {
console.log('Photo uploaded:', file.name);
}}
onProcessing={(jobId) => {
console.log('Processing:', jobId);
}}
onComplete={(result) => {
console.log('Result:', result.imageUrl);
analytics.track('tryon_completed', { jobId: result.jobId });
// Show success toast, trigger upsell, etc.
}}
onError={(error) => {
console.error('Try-on failed:', error.message);
// error.code: 'INSUFFICIENT_BALANCE' | 'API_ERROR' | etc.
Sentry.captureMessage(error.message);
}}
onClose={() => {
console.log('Modal closed');
}}
/>
CallbackArgumentsDescription
onOpenModal opened
onCloseModal closed
onUploadfile: FileCustomer uploaded a photo
onProcessingjobId: stringTry-on generation started
onComplete{ jobId, imageUrl }Result image ready
onError{ message, code? }An error occurred

Environment Variables

The component reads these environment variables automatically — no need to pass them as props:

VariableRequiredDescription
NEXT_PUBLIC_PRIMESTYLE_API_KEYYesYour PrimeStyle API key (starts with ps_live_)
NEXT_PUBLIC_PRIMESTYLE_API_URLNoCustom API URL (defaults to https://myaifitting.com/api)
.env.local
# .env.local
NEXT_PUBLIC_PRIMESTYLE_API_KEY=ps_live_your_key_here
# Optional: custom API URL
# NEXT_PUBLIC_PRIMESTYLE_API_URL=https://myaifitting.com/api

Internationalization (i18n)

The SDK ships built-in translations for 20 languages. Set the locale prop to control the language, or omit it to auto-detect from the browser.

tsx
// Auto-detect from browser language
<PrimeStyleTryon productImage="..." />
// Explicit locale
<PrimeStyleTryon productImage="..." locale="ja" />
// Web Component
<prime-style-tryon product-image="..." locale="fr"></prime-style-tryon>

Supported Locale Codes

CodeLanguage
enEnglish
esSpanish
frFrench
deGerman
itItalian
svSwedish
jaJapanese
csCzech
daDanish
nlDutch
noNorwegian
plPolish
pt-BRPortuguese (Brazil)
pt-PTPortuguese (Portugal)
fiFinnish
trTurkish
thThai
zh-CNChinese (Simplified)
zh-TWChinese (Traditional)
koKorean

Guides

Shopify App (No Code)

Install the PrimeStyle app from the Shopify App Store to add virtual try-on and AI-powered size recommendations to your product pages — no code or theme editing required.

1. Install the app

Search for "PrimeStyle Virtual Try-On" in the Shopify App Store and click Install. Authorize the app and it will automatically connect to your store — no API keys or configuration needed.

2. Activate on product pages

Once installed, the app automatically adds a "Virtual Try-On" button to all product pages in your store. The button appears next to your "Add to Cart" button. No theme editing needed — the app uses Shopify's app blocks system.

3. What your customers get

Virtual Try-On

Customers upload a photo and see themselves wearing the product. Results are generated in ~15 seconds with a progress bar and scanning animation.

AI Size Recommendation

Customers enter their measurements or height/weight for a quick estimate. The AI cross-references with the product's size guide to recommend the best fit, with confidence level and measurement-by-measurement breakdown.

4. Size guide auto-detection

The app automatically scans each product page for size guide data — in the product description, metafields, third-party size guide apps, and even size chart images. When a size guide is found, the AI uses it for precise sizing recommendations mapped directly to your chart.

5. Measurement profiles

Customers can save their body measurements as profiles for instant sizing on any product. Profiles are stored locally in the browser — no account required. Each profile saves measurements, unit preferences (cm/in), gender, and country.

Zero setup required. The Shopify app handles everything — product image detection, size guide extraction, try-on processing, and result display. No API keys needed. Usage and billing are managed automatically through the app.

Image Best Practices

Better input images = better try-on results. These apply to both the customer's photo (modelImage) and the garment images:

Do

  • Use product-only images (white/clean background)
  • Minimum 512px on shortest side
  • Front-facing, flat-lay, or mannequin shots
  • Well-lit, sharp, no watermarks
  • JPEG or PNG format, any size up to 50MB

Don't

  • Use images with models already wearing the garment
  • Use images smaller than 256px
  • Use heavily styled/filtered photos
  • Use images with multiple products
  • Use SVG or animated GIF format

One garment per request

Send a single garment image per request via the garmentImage field. The AI generates a photorealistic result of the customer wearing that product.

Handling Loading States

Virtual try-on typically takes 15-20 seconds. Here are patterns to keep users engaged:

Use SSE, not polling

The SSE stream delivers the result the instant it's ready — first as a base64 image for immediate display, then as a CDN URL for permanence. No wasted time between polls.

Progress indication

Show a shimmer skeleton of the result image while processing. The SDK handles this automatically. For API users, display a progress indicator with "~15 seconds remaining".

Keep them browsing

Let users continue shopping while the try-on processes. Use the SSE stream or SDK events to show a toast notification when the result is ready.

Retry gracefully

If a job fails (safety filter, timeout), the try-on is not counted against your balance. Show a friendly message with a retry button. The SDK handles this automatically.

Pricing

Simple pricing based on try-on generations. Subscribe for volume discounts. You are only charged for successful try-ons.

PlanPriceTry-Ons
Tier I$299/mo600
Tier IIPopular$999/mo2,500
Tier III$2,999/mo10,000

~15s

Average processing time

$0

Failed jobs are free

Auto

Refund on failed jobs

Support

We're here to help you integrate. Reach out through any of these channels:

Frequently Asked

What image formats are supported?

JPEG, PNG, and WebP. Both URLs and base64 data URIs. Max 50MB per file.

How many garments per request?

One garment per request. Send a single product image via the garmentImage field and get a photorealistic try-on result.

Do I need to send product images with the SDK?

No. The SDK auto-detects and extracts product images from your page using OG tags, Schema.org data, and smart heuristics. You can optionally override with the product-image attribute.

Do you store customer photos or garment images?

No. Customer photos and garment images are processed in memory and never stored. Only the generated result image is returned to you.

What happens if a try-on fails?

Failed try-ons are not counted against your balance. Common causes: safety filter blocks or invalid images. Check the status endpoint or listen for failed events on the SSE stream.

How long does processing take?

Typically 15-20 seconds. Use the SSE stream to receive the result the instant it's ready, or poll the status endpoint every 3 seconds as a fallback.

Data Processing Addendum

This Data Processing Addendum (“DPA”) forms part of the agreement between PrimeStyleAI (“Processor”) and the Customer (“Controller”) for the provision of the Services.

If there is a conflict between the DPA and the main agreement, the DPA controls for data protection matters.

1. Roles & Scope

1.1 Controller and Processor. Customer is the Controller of personal data processed via the Services. PrimeStyleAI acts as the Processor.

1.2 Purpose. Processor will process personal data only to provide the Services (render Outputs, secure the platform, and operate the developer portal).

1.3 Instructions. Customer instructs Processor to process personal data as necessary to provide the Services and as documented in the API/SDK documentation and this DPA.

2. Details of Processing

Annex 1 describes the subject matter, duration, nature and purpose of processing, types of personal data, and categories of data subjects.

Annex 1

Subject matter
AI-powered image rendering for virtual try-on outputs.
Duration
For the term of the agreement and as needed for transient processing.
Nature of processing
Receiving, transforming, and generating image outputs; logging for security and performance.
Purpose
Provide the Services; prevent abuse; ensure reliability.
Data subjects
Customer’s end users and Customer’s authorized users.
Types of data
User-uploaded images; product images; technical identifiers; account emails; logs.

3. Processor Obligations

  • Process personal data only on documented instructions from Customer, unless required by law.
  • Ensure persons authorized to process personal data are bound by confidentiality obligations.
  • Implement appropriate technical and organizational measures to protect personal data.
  • Assist Customer with responding to data subject requests, taking into account the nature of processing.
  • Assist Customer with DPIAs and consultations with regulators to the extent required and reasonably available.

4. Security Measures

Processor maintains reasonable measures appropriate to the risk. Annex 2 lists baseline controls.

Annex 2 — Baseline Security Controls

  • Encryption in transit (HTTPS/TLS).
  • Access controls and least-privilege administrative access.
  • Credential and key management practices (rotation recommended).
  • Monitoring, logging, and abuse prevention controls.
  • Separation of environments where feasible (e.g., dev/prod).

5. Subprocessors

Customer authorizes Processor to engage subprocessors to provide the Services (e.g., cloud hosting and AI infrastructure providers). Processor will impose data protection obligations on subprocessors consistent with this DPA and remains responsible for subprocessors' performance.

Processor will provide an up-to-date list of subprocessors upon request or via an attached schedule. Customer may object to a new subprocessor on reasonable data protection grounds by providing written notice within ten (10) days of notice.

6. International Transfers

Where personal data originating in the EEA/UK/Switzerland is transferred to a country without an adequacy decision, the Parties will implement appropriate safeguards, such as the EU Standard Contractual Clauses (SCCs) and/or the UK Addendum, typically incorporated by reference through this DPA or an exhibit.

7. Personal Data Breach

Processor will notify Customer without undue delay after becoming aware of a confirmed personal data breach affecting the Services. Processor will provide information reasonably necessary for Customer to meet any breach notification obligations.

8. Deletion & Return

Upon termination of the Services, Processor will delete or return personal data as requested by Customer, subject to applicable law and reasonable backups/archival practices. Transient user images are not intended to be stored persistently by default.

9. Audits

Upon reasonable prior notice and no more than once annually, Customer may audit Processor's compliance with this DPA to the extent necessary and proportionate, subject to confidentiality and security constraints. Processor may satisfy audit requests by providing summaries of controls, third-party reports (if available), or other reasonable evidence of compliance.

10. Liability

Each Party's liability under this DPA is subject to the limitations of liability in the main agreement, unless prohibited by applicable law.

Contact

admin@PrimeStyleAI.com28171 Westfield Drive, Laguna Niguel, CA 92677, USA
API Documentation | PrimeStyle AI Virtual Try-On