Back to Articles
Engineering

How to integrate TryOnKit with Headless Shopify

Doli Vadiya

Doli Vadiya

Technical Architect

April 28, 2026
How to integrate TryOnKit with Headless Shopify

Headless commerce represents the ultimate standard for modern, high-growth fashion brands. By decoupling the presentation layer from the e-commerce engine, engineers can craft blazing-fast storefronts using frameworks like React, Next.js, and Shopify Hydrogen. Integrating the TryOnKit SDK into a headless stack requires clean state synchronization, variant tracking, and robust client-side event orchestration.

Architectural Overview

In a typical Shopify headless environment, the product detail page (PDP) is dynamically generated during build time (SSR) or hydrated on-demand (ISR). Because the TryOnKit SDK performs intensive client-side activities like raw camera access, shopper image crops, and asynchronous API polling, it is essential to initialize the SDK safely inside the browser context without blocking server rendering.

Let's explore the data flow model for a seamless headless integration:

  • Step 1: The customer lands on the PDP. Shopify Hydrogen fetches metadata via the Storefront API.
  • Step 2: The TryOnKit embed script (embed.js) is lazy-loaded with your tk_emb_ embed key passed as a query param, exposing the global TryOnKit object.
  • Step 3: You call TryOnKit.init(), passing the targetElement selector to mount into, the active variant's productImage, and the product taxonomy (category + subCategory).
  • Step 4: Image upload or web-cam capture occurs. The browser sends client payloads securely to the TryOnKit API, scoped to your authorized domains, and emits lifecycle events like tryon:success.

The Plain HTML Embed

Before wiring it into React, it helps to see the canonical embed. The SDK is a single script loaded with your tk_emb_ embed key, plus a mount element and one TryOnKit.init() call. Product options are passed at the top level, while appearance options (colors and the button label) are grouped inside a theme object:

<!-- Load the TryOnKit embed SDK (embedKey required in the URL) -->
<script src="https://your-api.tryonkit.ai/api/v1/embed/embed.js?embedKey=tk_emb_your_key"></script>

<img id="product-image" src="https://cdn.yourstore.com/garment.jpg" alt="Product" />
<div id="tk-tryon-container"></div>

<script>
  TryOnKit.init({
    apiKey: "tk_emb_your_key",
    targetElement: "#tk-tryon-container",
    productId: "SKU-990",
    productImage: document.getElementById("product-image").src,
    category: "clothes",        // "clothes" | "footwear" | "accessories"
    subCategory: "tshirt",      // refines fit + drape simulation
    theme: {
      primaryColor: "#39D98A",
      secondaryColor: "#10B981",
      buttonText: "Try On Virtually",
    },
  });
</script>

Step-by-Step Implementation

In a headless React/Hydrogen storefront, wrap that same flow in a useEffect so it only runs client-side and re-initializes when the active variant changes. Here is a production-grade integration wrapper:

import { useEffect } from "react";

const EMBED_KEY = "tk_emb_your_key";
const EMBED_SRC =
  `https://your-api.tryonkit.ai/api/v1/embed/embed.js?embedKey=${EMBED_KEY}`;

interface TryOnButtonProps {
  productId: string;
  variantImage: string;
  category: "clothes" | "footwear" | "accessories";
  subCategory: string; // e.g. "tshirt", "jeans", "sneakers"
}

export function TryOnButton({ productId, variantImage, category, subCategory }: TryOnButtonProps) {
  useEffect(() => {
    // The SDK touches the DOM + camera — only run it in the browser.
    if (typeof window === "undefined") return;

    const mount = () => {
      window.TryOnKit?.init({
        apiKey: EMBED_KEY,
        targetElement: "#tk-tryon-container",
        productId,
        productImage: variantImage,
        category,
        subCategory,
        theme: {
          primaryColor: "#39D98A",
          secondaryColor: "#10B981",
          buttonText: "Try On Virtually",
        },
      });

      // Forward AI render completions into your analytics.
      window.TryOnKit?.on?.("tryon:success", (meta) => {
        console.log("Try-on generated:", meta.imageUrl);
      });
    };

    // Load the embed script once, then (re)initialize on every variant change.
    if (window.TryOnKit) {
      mount();
    } else {
      const script = document.createElement("script");
      script.src = EMBED_SRC;
      script.async = true;
      script.onload = mount;
      document.body.appendChild(script);
    }
  }, [productId, variantImage, category, subCategory]);

  return <div id="tk-tryon-container" className="w-full" />;
}

Handling Active Variant Updates

In modern fashion PDPs, shoppers toggle between various colorways and fabric patterns. Because each option corresponds to a completely different static image, your component must tell the SDK when to refresh the donor image.

We advise passing variantImage (and the taxonomy props) as reactive dependencies of the useEffect above. When a shopper switches variants, the effect re-runs and calls TryOnKit.init() again with the new productImage, immediately replacing the active product canvas without requiring the user to re-upload their photo.

"Performance optimization is paramount in headless commerce. By lazily loading the heavy canvas components only when a shopper actively selects try-on, you keep your core Core Web Vitals (LCP, INP, CLS) in the green."

Security: Domain Lock and Restricted API Scope

The tk_emb_ embed key is a public, client-side key by design — it ships in your page source. Because API calls consume generation credits, we enforce a strict Domain Authorization Policy inside your TryOnKit client dashboard. Even if an actor extracts your embed key, requests originating from unauthorized domains are automatically blocked. This preserves your subscription security and maintains perfect telemetry logs on custom headless storefronts.

Live Visual Testing

Ready to transform your boutique shop?

Join hundreds of forward-thinking merchants getting zero-friction fit matching.