Skip to main content

Widget & Try-on

The Genvoris widget lets your customers virtually try a product on with a single click. Server-side, every successful try-on debits your credit pool and the end-customer's per-period quota.

Drop-in script

Place this on any product page:

<button class="genvoris-tryon-btn" data-product-image="/img/dress.jpg">
Virtual Try-on
</button>

<script
src="https://cdn.genvoris.org/widget.js"
defer
data-api-key="gvk_live_xxxxxxxx"
data-end-customer-token="<%= sessionToken %>"
></script>
AttributeRequiredNotes
data-api-keyyesYour Genvoris store key, also enforced server-side
data-end-customer-tokenoptionalSession JWT — when present, per-customer quota is enforced

If you omit data-end-customer-token, the widget runs in legacy mode: every try-on debits your credit pool with no per-customer accounting.

Underlying flow

The widget calls your try-on backend, which forwards to Genvoris:

Browser ──▶ Your try-on backend ──▶ POST /api/tryon/track
(FastAPI / Node / etc) x-internal-secret: ...
api_key, end_customer_token, ...

/api/tryon/track is a server-to-server endpoint, not browser-callable. The x-internal-secret env shared between your try-on backend and the portal authenticates the call. If you're using our reference FastAPI backend, this is wired up for you.

Request body — POST /api/tryon/track

{
"api_key": "gvk_live_xxxxxxxx",
"product_type": "apparel",
"variation_count": 4,
"generation_time_ms": 1820,
"success": true,
"page_url": "https://shop.com/p/dress-42",
"product_title": "Black Wrap Dress",
"origin": "https://shop.com",
"end_customer_token": "eyJhbGciOiJSUzI1NiIs..."
}

end_customer_token is optional. When present:

  • We verify the JWT (iss=https://genvoris.org, aud=genvoris-widget).
  • The token's sid claim must equal the api key's owner; mismatched store ↔ token returns 403.
  • The customer's plan quota is enforced before debiting your pool. Insufficient quota = 402 + nothing debited.
  • After a successful debit, per-customer usage is incremented by 1.

Response

{
"success": true,
"remaining_credits": 4823,
"variation_count": 4,
"end_customer_quota": { "used": 33, "limit": 100, "remaining": 67 }
}

end_customer_quota is only present when an end-customer token was supplied.

Error matrix

HTTPerrorWhen
401unauthorizedBad x-internal-secret
401invalid_keyBad API key
401invalid_session_tokenJWT failed verification or expired
402credit_limit_reachedYour store's credit pool empty
402end_customer_quotaPer-customer plan exhausted (reason = quota_exhausted / no_plan / paused / cancelled)
403account_inactiveStore account suspended
403domain_not_allowedOrigin not whitelisted on the API key
403token_store_mismatchJWT's sid ≠ API key owner

Custom widget UX

You can build your own widget — call your backend, which calls /api/tryon/track. The Genvoris widget script is convenience; the API is the contract.