GuideBy Thibault Mathian

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:

  1. Upload the person photo with POST /images/upload. You get an imageId back and can reuse it for every try-on with that photo.
  2. Create the try-on with POST /try-on. Send the product inline (an image, a title and a description) and the imageId. There is no catalog to sync first.
  3. Get the result: poll GET /generations/:id, call waitFor() in the SDK, or receive a generation.completed webhook. 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:

  1. The app takes or picks a photo and sends it to your backend.
  2. Your backend uploads it to the API and starts the try-on.
  3. Your backend returns the result URL, or pushes it to the app when the webhook arrives.
  4. 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 externalId and the analysis is reused.
  • Keeping photos longer than needed. Set keepForDays to 1, 3 or 7 when you upload, and pass your own externalUserId so 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.