Skip to main content
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).

What you’ll build

Try-on button

A “Try it on” button on product pages that opens a realtime try-on modal with the user’s webcam.

Instant garment swap

Switch between products without reconnecting — each click sends a new garment image and prompt.

Secure tokens

Your permanent API key stays on the server. The browser only receives a short-lived ephemeral token.

Prerequisites

How it works

The entire integration is three steps:
  1. Server creates a short-lived client token from your permanent API key
  2. Browser opens the camera and establishes a WebRTC connection to lucy-vton-latest
  3. Browser sends a garment image + descriptive prompt via set() — the model dresses the person in realtime

Step 1: Create a client token (server-side)

Your backend creates a short-lived token using your permanent API key. The browser never sees your real key.
// app/api/tokens/route.ts
import { 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.

Step 2: Connect camera to the realtime model

The frontend fetches a token, opens the camera, and establishes a WebRTC connection to lucy-vton-latest.
import { createDecartClient, models } from "@decartai/sdk";

// 1. Get a client token from your backend
const res = await fetch("/api/tokens", { method: "POST" });
const { apiKey } = await res.json();

// 2. Open the user's camera
const stream = await navigator.mediaDevices.getUserMedia({
  video: { facingMode: "user" },
});

// 3. Connect to the realtime model
const client = createDecartClient({ apiKey });

const rtClient = await client.realtime.connect(stream, {
  model: models.realtime("lucy-vton-latest"),
  onRemoteStream: (remoteStream) => {
    document.getElementById("output").srcObject = remoteStream;
  },
});

Step 3: Send a garment image + prompt

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.

Product catalog pattern

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
  });
}

Prompt patterns

Use the substitute pattern when replacing an existing garment, and the add pattern when adding something new:
PatternWhen to useExample
SubstituteReplacing an existing garment"Substitute the current top with a red plaid flannel shirt with a relaxed fit"
AddAdding 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)

Generating prompts for user uploads

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.ts
import 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”).

Reference image tips

  • Clean garment images work best — just the clothing item, no person wearing it
  • White or plain backgrounds are ideal
  • At least 512×512 pixels — the model reproduces what it sees, so a clear image produces better results
  • If your product images show a model wearing the garment, consider using an image editing model to extract just the clothing item first

More examples

The tryon-examples repo includes six production-ready Next.js examples:
ExampleUse caseHighlights
E-commerce”Try it on” on product pagesPre-written prompts, modal overlay
StandaloneDedicated try-on experienceLLM-generated prompts from garment images
Person DetectionKiosks and unattended displaysAuto-connects only when someone is in frame
Full-FeaturedComplete try-on experiencePerson detection, clothing extraction, extreme precision
Digital MirrorIn-store kiosk / smart mirrorTwo-device setup (display + phone controller via QR code)
Outfit BuilderMulti-garment stylingCompose top + bottom garments into full outfits

Next steps

Virtual Try-On Guide

Full guide for realtime and batch virtual try-on, including all parameters and SDK examples.

Batch API Reference

Process pre-recorded videos asynchronously with the batch virtual try-on endpoint.

Client Tokens

Secure your integration with short-lived ephemeral tokens.

Streaming Best Practices

Optimize your realtime integration for the best experience.