Add a ‘Try it on’ button to product pages with realtime virtual try-on
Let shoppers see how clothing looks on them in realtime, using just a webcam. This walkthrough covers the key integration points for adding virtual try-on to an e-commerce product page — from creating secure client tokens to sending garment images with descriptive prompts.
This example uses Next.js, but the same @decartai/sdk works with any JavaScript framework.
Source code:github.com/DecartAI/tryon-examples — includes six production-ready examples (e-commerce, standalone, digital mirror, outfit builder, and more).
Your backend creates a short-lived token using your permanent API key. The browser never sees your real key.
// app/api/tokens/route.tsimport { createDecartClient } from "@decartai/sdk";import { NextResponse } from "next/server";export async function POST() { const client = createDecartClient({ apiKey: process.env.DECART_API_KEY, }); const token = await client.tokens.create(); return NextResponse.json(token);}
Client tokens have a 10-minute TTL. Create a new token each time a user opens a try-on session. Active WebRTC sessions continue working even after the token expires. See the Client Tokens guide for details.
Call set() to send a reference garment image with a descriptive prompt. The model applies the garment to the person in realtime.
await rtClient.set({ prompt: "Substitute the current top with a black bomber jacket with a blue logo on the chest and a zip front", image: garmentBlob, enhance: false,});
Call set() again at any time to switch garments — no need to reconnect.
For e-commerce, pre-write prompts for each product in your catalog. This gives the best results since you can craft specific, detailed descriptions.
interface Product { name: string; image: string; prompt: string; price: number;}const products: Product[] = [ { name: "Bomber Jacket", image: "/products/bomber.png", prompt: "Substitute the current top with a black bomber jacket with a blue logo on the chest and a zip front", price: 149, }, { name: "Knit Beanie", image: "/products/beanie.png", prompt: "Add a navy blue knit beanie with a white cross logo on the fold to the person's head", price: 35, }, { name: "Polo Shirt", image: "/products/polo.png", prompt: "Substitute the current top with a navy blue polo shirt with a white logo on the chest", price: 69, },];// When user clicks "Try it on"async function tryOn(product: Product) { const garmentBlob = await fetch(product.image).then((r) => r.blob()); await rtClient.set({ prompt: product.prompt, image: garmentBlob, enhance: false, // use your pre-written prompt as-is });}
Use the substitute pattern when replacing an existing garment, and the add pattern when adding something new:
Pattern
When to use
Example
Substitute
Replacing an existing garment
"Substitute the current top with a red plaid flannel shirt with a relaxed fit"
Add
Adding something the person isn’t wearing
"Add a wide-brimmed straw hat to the person's head"
Be specific — include color, material, texture, pattern, and fit. Aim for 20–30 words.
✅ "Substitute the current top with a bright red hoodie with an oversized casual fit"✅ "Add a navy baseball cap with a blue logo to the person's head"❌ "Put a jacket on the person" (too vague)❌ "Red hoodie" (missing action and context)
For user-uploaded garment images where you don’t have a pre-written prompt, use any vision LLM to auto-generate one from the garment image:
// app/api/enhance-prompt/route.tsimport OpenAI from "openai";const openai = new OpenAI();export async function POST(req: Request) { const formData = await req.formData(); const image = formData.get("image") as File; const personFrame = formData.get("personFrame") as File | null; // optional const messages = [ { role: "system" as const, content: `You write prompts for a virtual try-on model. Examine the garment image and write a prompt using this pattern:"Substitute the current top with [detailed garment description]" or "Add [item] to the person's [body part]".Include color, material, texture, pattern, and fit. 20-30 words. Return only the prompt.`, }, { role: "user" as const, content: [ { type: "image_url" as const, image_url: { url: await fileToDataUrl(image) } }, ...(personFrame ? [{ type: "image_url" as const, image_url: { url: await fileToDataUrl(personFrame) } }] : []), ], }, ]; const completion = await openai.chat.completions.create({ model: "gpt-4o-mini", messages, max_tokens: 100, }); return Response.json({ prompt: completion.choices[0].message.content });}
Sending a camera frame of the person alongside the garment image gives the LLM context about what they’re currently wearing, producing more accurate prompts (e.g. “Substitute the grey sweater” instead of generic “Substitute the current top”).