How to Add AI Virtual Try-On to Your App With an API
Generate a photo of a person wearing a specific garment, pair of glasses or necklace with one API call. Architecture, code in TypeScript, cURL and Python, mobile apps, costs and the mistakes to avoid.
Table of contents
A virtual try-on API takes two images, a photo of a person and a photo of a product, and returns a new photo of that person wearing the product. This guide shows how to add one to a web app, a mobile app or a custom store, using the Genlook Try-On API. The same flow works for clothing, shoes, glasses, jewelry, watches, bags and hats.
Disclosure: Genlook makes this API. If you are still choosing a provider, our benchmark of 10 try-on APIs shows every result side by side.
What you need
- An API key. Create an account on platform.genlook.app. New accounts get 10 free credits, enough to test the whole flow.
- A backend. The key must stay on a server, never in a browser or a mobile app bundle.
- A person photo: a JPEG, PNG, WebP or HEIC up to 10 MB, front-facing, with the body part that wears the product visible.
- A product image: the photo you already use on your product page. A packshot, a flat lay or an on-model photo all work. No 3D model is needed.
How the flow works
Every integration follows the same three steps:
- Upload the person photo with
POST /images/upload. You get animageIdback and can reuse it for every try-on with that photo. - Create the try-on with
POST /try-on. Send the product inline (an image, a title and a description) and theimageId. There is no catalog to sync first. - Get the result: poll
GET /generations/:id, callwaitFor()in the SDK, or receive ageneration.completedwebhook. The median time is about 8 seconds.
If you prefer a single request, POST /try-on/sync keeps the connection open until the result is ready and returns it directly. It fits scripts and serverless functions.
Your first try-on in TypeScript
The official SDK is @genlook/api. It runs on Node 20+, Deno, Bun and edge runtimes.
import { Genlook } from "@genlook/api";
import { readFile } from "node:fs/promises";
const client = new Genlook({ apiKey: process.env.GENLOOK_API_KEY! });
// 1. Upload the person photo once, reuse the imageId.
const { imageId } = await client.images.upload(
await readFile("./person.jpg"),
{ mimeType: "image/jpeg" },
);
// 2. Create the try-on. The product is created inline.
const { generationId } = await client.tryOn.create({
products: [{
externalId: "linen-shirt-12",
title: "Relaxed linen shirt",
description: "Oversized fit, dropped shoulders, falls below the hip.",
images: [{ source: { url: "https://cdn.example.com/linen-shirt.jpg" } }],
}],
person: { image: { source: { id: imageId } } },
});
// 3. Wait for the result.
const result = await client.generations.waitFor(generationId);
console.log(result.resultImageUrl);
The same call with cURL or Python
There is no Python SDK, but the REST API works from any language. This is the one-request version with the sync endpoint:
curl -X POST "https://api.genlook.app/tryon/v1/try-on/sync" \
-H "x-api-key: $GENLOOK_API_KEY" \
-H "Content-Type: application/json" \
--max-time 100 \
-d '{
"products": [{
"externalId": "linen-shirt-12",
"title": "Relaxed linen shirt",
"description": "Oversized fit, dropped shoulders, falls below the hip.",
"images": [{ "source": { "url": "https://cdn.example.com/linen-shirt.jpg" } }]
}],
"person": { "image": { "source": { "id": "<imageId>" } } }
}'
import os, requests
BASE = "https://api.genlook.app/tryon/v1"
headers = {"x-api-key": os.environ["GENLOOK_API_KEY"]}
with open("person.jpg", "rb") as f:
image_id = requests.post(f"{BASE}/images/upload", headers=headers,
files={"file": ("person.jpg", f, "image/jpeg")}).json()["imageId"]
result = requests.post(f"{BASE}/try-on/sync", headers=headers, timeout=100, json={
"products": [{
"externalId": "linen-shirt-12",
"title": "Relaxed linen shirt",
"description": "Oversized fit, dropped shoulders, falls below the hip.",
"images": [{"source": {"url": "https://cdn.example.com/linen-shirt.jpg"}}],
}],
"person": {"image": {"source": {"id": image_id}}},
}).json()
print(result["resultImageUrl"])
The sync request waits up to 90 seconds. If the result is still running after that, you get a 202 with the generationId and can poll for it.
Glasses, jewelry, shoes and other products
You don't pass a product type. The API reads the product image and places the item where it is worn: glasses on the face, earrings on the ears, a necklace around the collarbone, shoes on the feet. The request is the same as for a shirt.
Two things to know:
- Outfits are clothing only. You can send up to 4 clothing items in one try-on, like a top, trousers and a jacket. Glasses, hats, shoes, bags and jewelry go in their own try-on.
- The person photo has to show where the product goes. A head-and-shoulders selfie works for glasses and earrings, but not for shoes.
Mobile apps (iOS, Android, Flutter, React Native)
The key can't ship inside the app, so a mobile integration always goes through your backend:
- The app takes or picks a photo and sends it to your backend.
- Your backend uploads it to the API and starts the try-on.
- Your backend returns the result URL, or pushes it to the app when the webhook arrives.
- The app shows the result image.
Your backend can be anything that makes HTTP requests, so the app's language doesn't matter.
What it costs
Each try-on costs 1 credit, and failed try-ons are refunded. Pay as you go is $0.04 per try-on, in credit packs from $5 that never expire. Monthly plans bring it to $0.02 per try-on (Starter: $20 for 1,000), down to $0.015 on Scale ($300 for 20,000). The pricing estimator on the developers page calculates your monthly cost from your volume.
Mistakes to avoid
- Calling the API from the browser. Anyone could read your key. Always go through your backend.
- Sending a vague product title. The title and description tell the AI what the product is and how it fits. "Cropped wool cardigan, boxy fit" gives better results than "Item 4417".
- Re-sending the product every time. The first try-on of a product analyzes it, which adds a few seconds. After that, send only its
externalIdand the analysis is reused. - Keeping photos longer than needed. Set
keepForDaysto 1, 3 or 7 when you upload, and pass your ownexternalUserIdso you can delete one user's images in a single call when they ask. - Spending credits while you build. Send a product titled
mock: the API returns the person photo unchanged, quickly and for free, so you can test your UI.
FAQ
Questions, answered.
Is there an API that generates a photo of a person wearing a specific garment?↓
Yes. A virtual try-on API does exactly that: you send a photo of the person and a photo of the garment, and it returns the person wearing it. With Genlook it takes one request to the sync endpoint, or two with polling, and about 8 seconds.
Do I need 3D models of my products?↓
No. The API works from ordinary product photos, the same ones on your product pages.
Can I use the results commercially?↓
Yes. Genlook is a commercial API built for production use in stores and apps. Research models such as IDM-VTON and CatVTON are released under non-commercial licenses.
I run a Shopify, WooCommerce or PrestaShop store. Do I need the API?↓
No. The Genlook app, plugin or module adds try-on to your product pages without code. The API is for custom storefronts, mobile apps and other products.