Virtual Try-On

Inject a 'Try it on' button on product pages that opens an AI-powered preview — customers upload a photo and see the product on themselves (apparel, accessories) or in their space (furniture, decor).

Virtual Try-On adds a button to your product pages (next to "Add to cart", typically) that opens a modal. The shopper uploads a photo, the modal sends it to Gemini together with the product's cleanest catalog image, and a few seconds later they see an AI-generated preview of the product on themselves or in their environment.

The feature is configured per business and is shipped as part of the web chat widget — no extra script tag. Make sure the chat widget is deployed first.


How it works

  1. The widget script loads on a page and reads the merchant's webChatConfig. If the config has a virtualTryonButtonConfigurationId (the sentinel), the feature is globally enabled for the business.
  2. The widget fetches every variant configured for the business and walks them in priority order. The first variant whose pathRegex matches the current URL path is selected. A variant with no pathRegex is a catch-all that matches every page.
  3. Variants marked disabled are skipped entirely (use this to stage changes before going live).
  4. The widget looks up the product for the current URL. If no product can be loaded, or the product belongs to one of the variant's blacklisted categories, the button is not injected.
  5. Otherwise, the widget renders the variant's button HTML at the variant's CSS selector, in the variant's insertion position. Clicking it opens the modal HTML.
  6. When the customer uploads a photo, gives consent and submits, the widget calls the Octocom backend, which:
    • Runs the image picker over the product's catalog images, picking the first one classified as showing the product in isolation (vs. a lifestyle scene with people/props). Decisions are cached per (image URL, prompt) so we only classify each image once.
    • Sends the customer's photo + that product image + the variant's try-on prompt to Gemini and streams the generated image back to the modal.

Multiple variants per business are common — for example, an English variant gated to /en and a Greek variant gated to /el, or a furniture variant gated to /products/sofa- with one prompt and an apparel variant gated to /products/ with another.


Variants and priority

Variants are ordered by an integer priority — highest wins. Reordering them swaps their priorities; new variants are appended at the bottom of the list so they don't shadow anything the merchant already arranged.

The sentinel on webChatConfig.virtualTryonButtonConfigurationId is a global on/off switch for the business: if it's null, the feature is off everywhere regardless of how many variants exist. The first variant you create on a business is automatically linked to the sentinel (turning the feature on). When you delete the variant the sentinel points at, the sentinel is repointed at another remaining variant; when you delete the last variant, the sentinel is cleared and the feature turns off.

The sentinel only controls whether the feature is on — it does not decide which variant is used at runtime. That's always the URL-match step described above.


Per-variant configuration

Variant name

Internal label shown in the dashboard's variant list. Not visible to shoppers.

Target selector

CSS selector identifying where to inject the button on the product page — e.g. .product-form__buttons, #product-addtocart-button, or button[name="add"]. You can pass multiple comma-separated selectors; the first one that matches wins. Pick something stable across the merchant's product templates.

Insertion position

How to insert the button HTML relative to the matched element:

  • before — inserts the button as a sibling immediately before the target.
  • after — inserts the button as a sibling immediately after the target.
  • inside — appends the button as the last child of the target.
  • replace — replaces the target element entirely with the button.

Page targeting (pathRegex)

A regular expression matched against window.location.pathname (no host, no query string). Variants are tried top-to-bottom by priority; the first one whose regex matches wins. Common examples: ^/products/ to scope to product pages only, ^/el/ to scope to a locale prefix.

Leave pathRegex empty / null to make the variant a catch-all. Catch-alls should usually sit at the bottom of the priority list so they don't shadow more-specific variants.

Try-on prompt

Sent to Gemini alongside the customer's photo and the chosen product image. Use this to nudge the model toward your preferred output style, brand voice, or category-specific instructions (e.g. furniture variants typically tell the model to keep the customer's room as-is and only add the product; apparel variants tell it to keep the customer's pose and face). Leave empty / null to fall back to the bundled platform default.

Image picker prompt

Before generating the try-on image, the backend walks the product's catalog images one at a time and asks a cheap classifier model whether each image shows the product in isolation (plain/studio background) vs. in a lifestyle scene (rooms, people, props). The first image classified as "isolation" is used. If none qualify, the system falls back to the first product image.

You can tweak the classifier prompt to match the catalog — e.g. for furniture you want the model to treat "neutral white background, no people" as isolation; for apparel you want "garment on a mannequin or laid flat" as isolation. Decisions are cached per (image URL, prompt), so updating the prompt invalidates the cache for that variant only.

Leave empty / null to use the bundled platform default.

Category blacklist

A list of product category slugs / IDs to exclude the variant from. If the product on the current page belongs to any blacklisted category, the button is not injected. Common uses: hide try-on on swimwear / underwear / beauty products that don't work well with the model.

Leave empty to apply to all categories.

Custom HTML (button and modal templates)

The button and modal are HTML templates you write. Style them however you want; the widget doesn't inject any default CSS. You can leave either field empty to fall back to the bundled platform default, which is a minimal, brand-neutral starting point.

You don't write any JavaScript — the widget finds elements by their data-octocom-tryon-* attributes at runtime and binds state and event handlers to them. Anything without a marker is treated as decoration and rendered as-is.

Button template markers
MarkerElementPurpose
data-octocom-tryon-trigger<button> / <a> / <div>Preferred click target. If absent, the open-modal handler attaches to the first <button>, <a>, or [role=button] instead. If none of those exist either, the entire template becomes the click target.
MarkerElementPurpose
data-octocom-tryon-step="form|loading|result|error"<div> / <section>Step container. Only the matching step is visible at a time; the others are hidden via display:none. Set the inline display (e.g. flex, grid) on each step container — it's captured at hydration and restored when the step becomes visible.
data-octocom-tryon-backdropoutermost <div>Click-to-close backdrop. Clicks landing directly on this element (not on its children) close the modal.
data-octocom-tryon-close<button>Close button. Multiple are fine — each one closes the modal.
data-octocom-tryon-photo-input<input type="file">Hidden file input. Wrap it in a <label> so clicking the label opens the picker natively.
data-octocom-tryon-photo-empty<div> / <label>Container shown when no photo is selected (e.g. the dropzone). Hidden after a photo is uploaded.
data-octocom-tryon-photo-filled<div>Container shown after a photo is uploaded (e.g. preview thumbnail row). Hidden when no photo is selected.
data-octocom-tryon-photo-preview<img>Image element whose src is set to the uploaded photo's object URL.
data-octocom-tryon-photo-nameany elementElement whose textContent is set to the uploaded file's name.
data-octocom-tryon-photo-replace<button>Click clears the uploaded photo and returns to the empty state.
data-octocom-tryon-consent<input type="checkbox">Consent checkbox. Add as many as you need — submit stays disabled until all of them are checked.
data-octocom-tryon-submit<button>Submit button. The widget toggles its disabled attribute based on consent + photo, and binds the click handler that triggers generation.
data-octocom-tryon-user-hint<input> / <textarea>Optional free-text input. Whatever the customer types is appended to the try-on prompt as additional hints (e.g. "place the sofa in front of the window"). Omit the element entirely if you don't want this.
data-octocom-tryon-form-error<div> / <p>Inline error container on the form step (e.g. file too big). Starts hidden; the widget sets textContent and shows it when needed.
data-octocom-tryon-result-image<img>Image element on the result step. src is set to the generated try-on result.
data-octocom-tryon-error-message<div> / <p>Element on the error step whose textContent is set to the server's error message.
data-octocom-tryon-retry<button>Click resets the form (clears photo + consents) and returns to the form step. Works on both result and error steps.

Missing markers degrade gracefully — e.g. omit -photo-preview and there just won't be a thumbnail.


Managing via MCP

Six MCP tools cover the full lifecycle:

ToolPurpose
list_virtual_tryon_configsList a business's variants, ordered by priority (highest first).
get_virtual_tryon_configFetch a single variant by ID, including prompts and HTML templates.
create_virtual_tryon_configCreate a new variant. Requires the business to already have a webChatConfig. Appended at the bottom of the priority list. First variant on a business is linked to the sentinel (feature turns on).
update_virtual_tryon_configPartial update — only fields you provide are changed. To clear a nullable text field (pathRegex, prompt, imagePickerPrompt, buttonHtmlTemplate, modalHtmlTemplate), pass null or an empty string. Does not touch priority.
reorder_virtual_tryon_configsSet priority order for the business. Pass every variant ID in the desired order — first ID gets the highest priority.
delete_virtual_tryon_configDelete a variant. If the sentinel pointed at it, the sentinel is repointed at another remaining variant; if it was the last variant, the sentinel is cleared and the feature turns off.

A typical end-to-end MCP flow for setting up a new business:

  1. Confirm webChatConfig exists for the business (the web chat must be deployed first).
  2. create_virtual_tryon_config with enabled: false and a sensible selector + insertion position. Leave prompt, imagePickerPrompt, and the HTML templates empty to start with the platform defaults.
  3. Iterate on prompt (and, if needed, imagePickerPrompt) via update_virtual_tryon_config until the generated images look right.
  4. Customize buttonHtmlTemplate / modalHtmlTemplate for the merchant's brand — keep the data-octocom-tryon-* markers from the defaults.
  5. Set enabled: true once you're happy with the output.
  6. Repeat from step 2 for any additional variants (per-locale, per-category, etc.) and use reorder_virtual_tryon_configs to put the most-specific variants on top.

On this page