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:
| Key | Looks like | Use it |
|---|---|---|
| Publishable | pk_live_… | In the browser (widget, Shopify theme). Works only on your registered domains. |
| Secret | sk_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)
- Shopify admin → Online Store → Themes → ⋯ → Edit code.
- Open
layout/theme.liquidand paste this just before</body>:<script src="https://tryon.klothai.com/widget.js" data-key="pk_live_YOUR_KEY" defer></script> - 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>
| Attribute | On | Meaning |
|---|---|---|
data-key | script | Your publishable key (required) |
data-color | script | Button / accent colour, e.g. #7a3e2b (default black) |
data-auto="false" | script | Don't add the automatic Shopify button |
data-garment | div | Product image URL (https). Best: a clean product or flat-lay photo |
data-description | div | Optional short text, e.g. “navy slim-fit chinos” |
data-label | div | Button text |
data-worn | div | Optional, 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"}'
| Field | Notes | |
|---|---|---|
person | required | Base64 JPEG/PNG of the shopper (a data: URL is fine). Resize to ≤ 1024 px; max ~1.6 MB. |
garment or garment_url | one required | The product image as base64, or an https URL we download. |
garment / garment_url as arrays | optional | Up to 3 product photos (front, back, detail). They are combined into one reference. |
garment_worn or garment_worn_url | optional, recommended | Up 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. |
description | optional | Up 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
| HTTP | Meaning |
|---|---|
| 400 | Missing or unreadable image / bad garment_url |
| 401 | Missing, wrong or disabled key |
| 402 | Monthly try-on limit reached |
| 403 | Publishable key used on a domain that is not registered, or secret key used from a browser |
| 413 | Image too large — resize to ≤ 1024 px |
| 429 | Too many requests per minute |
| 502 | Temporary problem starting the job — retry |
Consent (required)
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
- Timing: about 25–45 s per image when warm. After a quiet period the first image can take 3–5 minutes while a GPU starts.
- Best input: shopper facing the camera, upper body or full length, good light; garment as a clean product or flat-lay photo.
- Garments: shirts, T-shirts, tops, trousers, dresses, kurtas. The garment type is detected automatically.
- Privacy: shopper photos are never saved to disk or used for training. The GPU worker deletes them right after the image is made, and the job (photo and result) expires from the processing queue within 1 hour.
- Limits: a monthly try-on quota and a per-minute rate limit per client. Failed try-ons are not counted.