Integration guidelines
Embed the Headless Editor in a page, initialize it, respond to lifecycle events, and finish a customization session by collecting a cart line item. The guidelines cover all initialization scenarios that the editor supports, including restore flows.
Embed the editor
The Headless Editor is a web component distributed as a bundle managed on Aurigma's CDN. The editor has no UI of its own except the design viewer, so the element that hosts it stays mostly invisible.
-
Add the editor tag to the page.
<au-headless-editor></au-headless-editor>Place the element in the container where you want to show the design viewer, for example next to the product image.
-
Load the script and stylesheet for the Customer's Canvas environment that matches your tenant.
const environment = "us"; // "us", "eu", or "au"const baseUrl = `https://staticjs-aurigma.azureedge.net/libs/${environment}/workflow-elements/headless-editor`;const stylesheet = document.createElement("link");stylesheet.rel = "stylesheet";stylesheet.href = `${baseUrl}/styles.css`;document.head.appendChild(stylesheet);const script = document.createElement("script");script.src = `${baseUrl}/index.js`;script.defer = true;document.head.appendChild(script); -
Wait for the custom element and get the editor instance.
import type { IHeadlessEditor } from "@aurigma/workflow-elements/headless-editor";await customElements.whenDefined("au-headless-editor");const editor = document.querySelector("au-headless-editor") as (HTMLElement & IHeadlessEditor) | null;The
@aurigma/workflow-elementspackage provides the TypeScript declarations for your host application. The web component itself is loaded from the CDN.
Initialize the editor
Call init() with the input, integration, and optional settings. Subscribe to lifecycle events before calling init().
import type { IHeadlessEditorInitArgs } from "@aurigma/workflow-elements/headless-editor";
editor.addEventListener("load", () => {
// The product and its initial design are ready.
});
editor.addEventListener("error", event => {
console.error("Headless Editor failed to initialize.", (event as CustomEvent<Error>).detail);
});
const configuration: IHeadlessEditorInitArgs = {
configVersion: 2,
input: {
productReferenceId: "<product_reference_id>",
},
integration: {
tenantId: <tenant_id>,
storefrontId: <storefront_id>,
cchubUrl: "https://customerscanvashub.com",
cchubApiGatewayUrl: "https://api.customerscanvashub.com",
user: {
id: "<storefront_user_id>",
token: "<storefront_user_token>",
},
},
};
await editor.init(configuration);
init() starts loading asynchronously and resolves to true when the product is loaded. Use the load event as the signal that the product and its initial design are ready. The method also accepts an optional forceReset argument that forces the editor to reset its state before the initialization.
The integration block tells the editor which tenant and storefront to use, and supplies the storefront user credentials. The optional quantity property defines the quantity applied to the resulting line item. The settings block controls the built-in viewer states; see Viewer settings and appearance.
Open a product by product reference
Pass productReferenceId to load a product through a product reference that links an external product ID, such as a Shopify product ID, to a Customer's Canvas product. This is the default integration flow for a storefront.
await editor.init({
configVersion: 2,
input: {
productReferenceId: "<product_reference_id>",
},
integration: { /* ... */ },
});
Optionally narrow the returned design variants with designVariantFilter, whose fields match the Storefront API product variant designs endpoint.
input: {
productReferenceId: "<product_reference_id>",
designVariantFilter: {
sku: "ABC-1234",
},
},
Open a product by product ID
When your integration already knows the Customer's Canvas PIM product ID, pass productId.
await editor.init({
configVersion: 2,
input: {
productId: <product_id>,
productVersionId: <product_version_id>,
},
integration: { /* ... */ },
});
productVersionId is optional. When you omit it, the editor uses the active product version.
Restore a saved design
To continue an existing customization session, pass the saved design together with the product data. The editor supports two restore mechanisms: restore by PIM product data and restore by product reference.
Restore by PIM product data
Use this approach when your integration knows the Customer's Canvas product ID and the product version where the design was created. Use the SKU variant when your catalog identifies the variant by SKU.
await editor.init({
configVersion: 2,
input: {
designId: "<design_id>",
productId: <product_id>,
productVersionId: <product_version_id>,
sku: "ABC-1234",
},
integration: { /* ... */ },
});
Use the variant ID variant when your catalog identifies the variant by its productVariantId.
await editor.init({
configVersion: 2,
input: {
designId: "<design_id>",
productId: <product_id>,
productVersionId: <product_version_id>,
productVariantId: <product_variant_id>,
},
integration: { /* ... */ },
});
Restore by product reference
Use this approach when your integration loads products through a product reference, for example, in a standard e-commerce integration. Pass productReferenceId together with the saved design ID. In this case, you don't need productVersionId — the editor resolves the product and its version through the product reference.
Use the SKU variant when your catalog identifies the variant by SKU.
await editor.init({
configVersion: 2,
input: {
productReferenceId: "<product_reference_id>",
designId: "<design_id>",
sku: "ABC-1234",
},
integration: { /* ... */ },
});
Use the variant ID variant when your catalog identifies the variant by its productVariantId.
await editor.init({
configVersion: 2,
input: {
productReferenceId: "<product_reference_id>",
designId: "<design_id>",
productVariantId: <product_variant_id>,
},
integration: { /* ... */ },
});
Both restore approaches also accept the optional designVariantTemplateId field. Pass the ID of the public template from which the design variant was created to indicate to the editor which design variant the user selected.
Respond to lifecycle events
The host application renders the controls for product options, design variants, and design elements. The editor provides the current state through its public API and notifies the host application when that state changes through CustomEvent objects whose payload is in the detail property.
Subscribe to the events before calling init(). The same events fire when the current product is later changed through openProduct().
| Event | detail | Use it to |
|---|---|---|
load | — | signal that the product and its initial design are ready |
productchanged | Product | rebuild product controls and re-read options |
variantchanged | ProductVariant | rebuild the design variant selector |
optionchoiceschanged | option choices | refresh the displayed option selection |
designvariantchanged | DesignVariant | rebuild the controls for the current design |
surfacechanged | Surface | rebuild the controls for the current surface |
addtocart | LineItem | submit the finished customization |
error | Error | show an error message or reset the loading state |
import type { DesignVariant, Product, ProductVariant } from "@aurigma/workflow-elements/headless-editor";
editor.addEventListener("productchanged", event => {
const product = (event as CustomEvent<Product>).detail;
const choices = editor.getChoices();
renderProductOptions(product.options, choices);
});
editor.addEventListener("variantchanged", event => {
const variant = (event as CustomEvent<ProductVariant>).detail;
renderDesignVariants(variant.designVariants);
});
editor.addEventListener("designvariantchanged", event => {
const designVariant = (event as CustomEvent<DesignVariant>).detail;
refreshDesignControls(designVariant);
});
Here, renderProductOptions(), renderDesignVariants(), and refreshDesignControls() represent functions implemented by your application.
Finish a customization session
When the customer finishes, the editor saves the current design and produces a line item. The line item identifies the selected product and variant and contains the private design ID required to create a Customer's Canvas project.
The event-driven flow matches the other editors. Subscribe to addtocart, and call addToCart() from the host application's button.
import type { LineItem } from "@aurigma/workflow-elements/headless-editor";
editor.addEventListener("addtocart", async event => {
const lineItem = (event as CustomEvent<LineItem>).detail;
await submitLineItem(lineItem);
});
document.querySelector("#add-to-cart")?.addEventListener("click", async () => {
await editor.addToCart();
});
addToCart() saves the current design and emits addtocart with the resulting line item in event.detail. It does not communicate with an e-commerce platform itself. Your handler creates a Customer's Canvas project and adds the item to the storefront cart.
If the event flow is not convenient, call getLineItem() and process its result directly.
const lineItem = await editor.getLineItem();
await submitLineItem(lineItem);
getLineItem() also saves the current design, but returns the line item without emitting addtocart. Use either the event-driven or the direct-return flow for a single user action to avoid processing the same customization twice.
The LineItem carries product and variant identifiers, the SKU, the quantity, and the saved state in properties:
_stateId— the identifiers of the saved design states._userId— the storefront user ID._hidden— internal values such as the design snapshot and generated images.
Send this line item to a trusted backend and create a Customer's Canvas project there, as shown in the quick start. See Projects for the project concept.
Update configuration after initialization
Call update() to change settings or resources without a full reinitialization. update() receives the same shape as init(), but you should only pass the settings or resources you want to replace.
editor.update({
settings: {
viewer: {
itemManipulationEnabled: false,
},
},
});
Updating the product input is not intended because it would discard the current customization progress. To open another product, use openProduct(), which is covered in Products, options, and variants.
Reference
- IHeadlessEditorInitArgs — the full configuration shape.
- HeadlessEditorInput — the input types.
- LineItem — the line item model.
- IHeadlessEditor — the component method reference.