Virtual Try-On API

Show shoppers themselves wearing your product. One photo of the shopper + one product image → a photo of the shopper wearing it.

Keys

Each store or app gets two keys:

KeyLooks likeUse it
Publishablepk_live_…In the browser (widget, Shopify theme). Works only on your registered domains.
Secretsk_live_…Only on your server or mobile-app backend. Never put it in a web page or app bundle.

Shopify (2 minutes, no app install)

  1. Shopify admin → Online Store → Themes → ⋯ → Edit code.
  2. Open layout/theme.liquid and paste this just before </body>:
    <script src="https://tryon.klothai.com/widget.js" data-key="pk_live_YOUR_KEY" defer></script>
  3. Save. A “Try it on” button appears under Add to cart on every product page, using the product's main image.

Choose exactly where the button goes (optional)

Add this where you want it in your product section (for example sections/main-product.liquid). The automatic button is then not added.

<div data-tryon
     data-garment="{{ product.featured_image | image_url: width: 1024 }}"
     data-description="{{ product.title | escape }}"
     data-worn="{% for img in product.images offset: 1 limit: 2 %}{{ img | image_url: width: 1024 }}{% unless forloop.last %},{% endunless %}{% endfor %}"
     data-label="Try it on"></div>

data-worn above passes the 2nd and 3rd product images as "worn" guides. Use it if those are photos of a model wearing the item; otherwise remove it.

Tip: register both your .myshopify.com domain and your custom domain for the publishable key. To hide the button on non-clothing products, use the data-tryon snippet inside {% if product.type == 'Shirts' %} … and add data-auto="false" to the script tag.

Any website

<div data-tryon data-garment="https://yourstore.com/images/shirt-123.jpg"
     data-description="white floral half-sleeve shirt"></div>
<script src="https://tryon.klothai.com/widget.js" data-key="pk_live_YOUR_KEY" defer></script>
AttributeOnMeaning
data-keyscriptYour publishable key (required)
data-colorscriptButton / accent colour, e.g. #7a3e2b (default black)
data-auto="false"scriptDon't add the automatic Shopify button
data-garmentdivProduct image URL (https). Best: a clean product or flat-lay photo
data-descriptiondivOptional short text, e.g. “navy slim-fit chinos”
data-labeldivButton text
data-worndivOptional, recommended: up to 3 comma-separated URLs of photos of a model wearing the item. Used as a guide for length, fit, belt/tie and drape that a flat product photo can't show.

REST API

Base URL: https://tryon.klothai.com/api/v1. JSON in, JSON out. It is asynchronous: start a job, then poll it every 2–3 seconds.

POST /tryon — start a try-on

curl -X POST https://tryon.klothai.com/api/v1/tryon \
  -H "Authorization: Bearer $TRYON_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"person": "<base64 JPEG>",
       "garment_url": "https://cdn.shopify.com/s/files/.../shirt.jpg",
       "description": "white floral half-sleeve shirt"}'
FieldNotes
personrequiredBase64 JPEG/PNG of the shopper (a data: URL is fine). Resize to ≤ 1024 px; max ~1.6 MB.
garment or garment_urlone requiredThe product image as base64, or an https URL we download.
garment / garment_url as arraysoptionalUp to 3 product photos (front, back, detail). They are combined into one reference.
garment_worn or garment_worn_urloptional, recommendedUp to 3 photos of a model wearing the item (base64 or https URLs, single value or array). The result copies how it is worn: length, fit, belt/tie, drape.
descriptionoptionalUp to 200 characters. Helps with colour and sleeve length.

Response 202:

{"id": "769e7545-…-e1", "status": "IN_QUEUE", "usage": {"used": 12, "limit": 1000}}

GET /tryon/{id} — get the result

curl https://tryon.klothai.com/api/v1/tryon/769e7545-…-e1 \
  -H "Authorization: Bearer $TRYON_SECRET_KEY"
{"id": "…", "status": "IN_QUEUE"}            // waiting for a GPU
{"id": "…", "status": "IN_PROGRESS"}         // generating
{"id": "…", "status": "COMPLETED", "image": "<base64 JPEG>", "seconds": 25.8}
{"id": "…", "status": "FAILED", "error": "…"}   // not counted against your limit

Results are available for about 1 hour after completion; save the image if you need it longer.

GET /usage

{"client": "mystore-a1b2", "month": "2026-10", "used": 412, "limit": 1000}

Example (Node.js server)

const API = "https://tryon.klothai.com/api/v1";
const H = { Authorization: `Bearer ${process.env.TRYON_SECRET_KEY}`, "Content-Type": "application/json" };

export async function tryOn(personBase64, garmentUrl, description) {
  const start = await fetch(`${API}/tryon`, { method: "POST", headers: H,
    body: JSON.stringify({ person: personBase64, garment_url: garmentUrl, description }) });
  const { id, error } = await start.json();
  if (!start.ok) throw new Error(error);
  for (;;) {
    await new Promise(r => setTimeout(r, 2500));
    const s = await (await fetch(`${API}/tryon/${id}`, { headers: H })).json();
    if (s.status === "COMPLETED") return Buffer.from(s.image, "base64");   // JPEG bytes
    if (s.status === "FAILED") throw new Error(s.error);
  }
}

Errors

HTTPMeaning
400Missing or unreadable image / bad garment_url
401Missing, wrong or disabled key
402Monthly try-on limit reached
403Publishable key used on a domain that is not registered, or secret key used from a browser
413Image too large — resize to ≤ 1024 px
429Too many requests per minute
502Temporary problem starting the job — retry

Before sending a photo, get the shopper's confirmation that they are 18 or over, or the parent/guardian of any child in the photo, and that everyone pictured agreed. The widget shows this checkbox and will not start without it. If you call the API directly, show an equivalent checkbox in your own app. This is required under India's DPDP Act (verifiable parental consent for under-18s) and similar laws elsewhere.

Timing, limits & privacy