Viewer – Intégration de base à votre site

Intégration en plein écran

Intégrez Viewer où vous le souhaitez sur votre site à l’aide d’un iframe.

Important : l’environnement d’intégration actuel nécessite une négociation postMessage et un jeton de session d’intégration de courte durée. Ce jeton est créé par votre serveur via l’API publique d’Alter Product et est lié à l’origine du site hôte.

Déroulement :

  1. Votre page charge l’iframe avec l’URL de Viewer.
  2. L’iframe envoie ALTER_CHILD_HELLO et votre page répond par ALTER_PARENT_ACK avec le même nonce.
  3. L’iframe demande l’accès avec ALTER_TOOL_INIT_SESSION et payload.tool=viewer.
  4. Votre serveur crée un jeton de session d’intégration et votre page envoie ALTER_TOOL_SESSION_READY avec token.
<!DOCTYPE html>
<html>
  <head>
    <title>Alter Product - Full Screen Embed</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      * { box-sizing: border-box; }
      html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
      iframe { width: 100%; height: 100%; border: 0; display: block; }
      #wrapper { width: 100%; height: 100%; }
    </style>
  </head>
  <body>
    <div id="wrapper">        
      <iframe
        id="alter-iframe"
        title="Alter Product Tool"
        src="https://alterproduct.com/app/viewer/1"
        allowfullscreen
      ></iframe>
    </div>
    <script>
      const IFRAME_ORIGIN = "https://alterproduct.com";
      const TOOL = "viewer";
      const DESIGN_ID = 1;
      const iframe = document.getElementById("alter-iframe");

      // Keep nonce per handshake (from iframe) to prevent random messages from being accepted.
      let handshakeNonce = "";
      let handshakeOk = false;

      function postToIframe(payload) {
        iframe.contentWindow.postMessage(payload, IFRAME_ORIGIN);
      }

      /**
       * Your backend owns this endpoint. It should call:
       * POST https://alterproduct.com/public-api/v1/embed/session
       * using server-side Alter Product API credentials.
       */
      async function createEmbedSessionFromYourBackend(payload) {
        const res = await fetch("/api/alter/embed-session", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(payload || {})
        });

        if (!res.ok) throw new Error("Failed to create embed session");
        const data = await res.json();

        // Expected response: { token: "..." }
        if (!data || !data.token) throw new Error("Missing token");
        return data.token;
      }

      window.addEventListener("message", async (event) => {
        // ✅ 1) Always validate origin
        if (event.origin !== IFRAME_ORIGIN) return;

        // ✅ 2) Always validate source
        if (event.source !== iframe.contentWindow) return;

        const msg = event.data || {};

        // -----------------------
        // A) HANDSHAKE
        // iframe -> parent: ALTER_CHILD_HELLO { nonce }
        // parent -> iframe: ALTER_PARENT_ACK  { nonce }
        // -----------------------
        if (msg.type === "ALTER_CHILD_HELLO") {
          if (!msg.nonce || typeof msg.nonce !== "string") return;

          handshakeNonce = msg.nonce;
          handshakeOk = true;

          postToIframe({ type: "ALTER_PARENT_ACK", nonce: handshakeNonce });
          return;
        }

        // Ignore everything until handshake is done
        if (!handshakeOk) return;

        // -----------------------
        // B) TOKEN REQUEST (on-demand)
        // iframe -> parent: ALTER_TOOL_INIT_SESSION
        //   payload: { tool, mode, uiDesignId }
        //
        // parent -> iframe: ALTER_TOOL_SESSION_READY
        //   { token }
        // -----------------------
        if (msg.type === "ALTER_TOOL_INIT_SESSION") {
          try {
            const payload = msg.payload || {};

            const tool = String(payload.tool || TOOL).toLowerCase();
            const designId = Number(payload.uiDesignId || DESIGN_ID);

            const token = await createEmbedSessionFromYourBackend({
              tool,
              designId,
              origin: window.location.origin
            });

            postToIframe({
              type: "ALTER_TOOL_SESSION_READY",
              token
            });
          } catch (e) {
            postToIframe({
              type: "ALTER_TOOL_SESSION_ERROR",
              message: String(e && e.message ? e.message : e)
            });
          }
          return;
        }

        // -----------------------
        // C) OPTIONAL: listen to tool events (examples)
        // -----------------------
        if (msg.type === "ALTER_VIEWER_ADD_TO_CART") {
          console.log("[Alter] Add to cart:", msg.payload);
          return;
        }
      });
    </script>
  </body>
</html>

Styles de base

Vous pouvez personnaliser Viewer de deux manières :

  • Avec des paramètres d’URL – configurez l’arrière-plan, l’environnement, l’éclairage, la navigation, la visibilité du bouton Ajouter au panier et la présélection des variantes (voir Styles (paramètres d’URL)).
  • Avec du CSS appliqué au conteneur entourant l’iframe (dimensions, bordures, arrondis, disposition).
#wrapper {
  height: 320px;
  width: 400px;
  overflow: hidden;
  border-radius: 14px;
  background: linear-gradient(0deg, rgba(0,43,133,1) 0%, rgba(0,182,215,1) 100%);
}

iframe {
  width: 100%;
  height: 100%;
  display: block;
  border: 0;
}