Install Sign Customiser on a headless Shopify storefront
Connect Sign Customiser to a Storefront API or Hydrogen cart outside a Shopify Online Store theme.
Last updated:
This guide is for developers who manage a headless Shopify storefront.
It explains how to show Sign Customiser and add the generated product to the existing Shopify cart.
Do not use this guide for a custom Liquid template. Use Choose a Shopify installation method instead.
Before you start
You need:
-
Sign Customiser connected to the same Shopify store.
-
The Sign Customiser ID.
-
A Storefront API or Hydrogen cart integration.
-
The presentment currency and its conversion rate.
-
The active Shopify market when you use Shopify Markets.
Never put a private Storefront API token in browser code.
1. Select the Shopify publication
Sign Customiser creates a new Shopify product when the customer selects Add to Cart.
The product must be available to the sales channel that serves your headless storefront.
-
In Sign Customiser, go to Tools & Settings > Integrations and Webhooks.
-
Open the Shopify integration.
-
Select Edit Integration.
-
Set Publication to the publication used by your headless storefront.
-
Save the integration.
If you do not select a publication, Sign Customiser uses Online Store when it is available.
2. Add the iframe
Build the iframe URL with URLSearchParams.
<iframe id="sign-customiser" title="Sign customiser" style="border: 0; display: block; min-height: 800px; width: 100%"></iframe>const signCustomiserOrigin = "https://web.signcustomiser.com";const iframe = document.querySelector("#sign-customiser");const params = new URLSearchParams({ client: "headless-shopify", currency_code: storefront.currencyCode, currency_rate: String(storefront.currencyRate),});if (storefront.currencyFormat) { params.set("currency_format", storefront.currencyFormat);}if (storefront.marketId && storefront.marketHandle) { params.set("shopify_market_id", String(storefront.marketId)); params.set("shopify_market_handle", storefront.marketHandle);}iframe.src = `${signCustomiserOrigin}/embed/${customiserId}?${params}`;Use a positive currency_rate. Use 1 when the presentment currency is the store base currency.
The rate must convert a price from the store base currency to the presentment currency.
If you use Shopify Markets, send both shopify_market_id and shopify_market_handle.
3. Send the storefront context
Listen for the spcReady message. Then send the current page and Shopify context to the iframe.
function sendStorefrontContext() { iframe.contentWindow?.postMessage( { type: "setHostUrl", hostUrl: window.location.href, shopifyContext: { marketHandle: storefront.marketHandle, marketId: storefront.marketId, }, }, signCustomiserOrigin, );}window.addEventListener("message", async (event) => { if ( event.origin !== signCustomiserOrigin || event.source !== iframe.contentWindow ) { return; } if (event.data?.type === "spcReady") { sendStorefrontContext(); }});iframe.addEventListener("load", sendStorefrontContext);The origin of hostUrl must match the origin of the page that sends this message.
4. Connect the Shopify cart
Sign Customiser sends sc:product:created after it creates the Shopify product.
Use product.external_data.variant_gid as the Storefront API merchandiseId.
Copy every productFormatted entry to the cart-line attributes. Keep keys that start with an underscore.
async function addSignCustomiserProduct(message) { const variantGid = message.product?.external_data?.variant_gid; if (!variantGid) { throw new Error("The generated product has no Shopify variant GID."); } const attributes = Object.entries(message.productFormatted ?? {}).map( ([key, value]) => ({ key, value: String(value ?? "") }), ); await storefrontCart.addLines([ { merchandiseId: variantGid, quantity: 1, attributes, }, ]);}storefrontCart.addLines represents your existing cart function. It must create a cart when no cart exists.
For Hydrogen, connect this function to the Hydrogen cart handler. For another framework, use cartCreate or cartLinesAdd.
Read Shopify’s documentation for Hydrogen cart handlers and cartLinesAdd.
Check the returned cart and its userErrors. Reject the operation when Shopify does not add the line.
5. Report the cart result
Report the result before you open the cart or change the page.
Wait for the matching sc:cart:result:ack message. Use a short timeout so that reporting does not block the customer.
function reportCartResult(checkoutAttemptId, result) { return new Promise((resolve) => { const timeout = window.setTimeout(finish, 400); function finish() { window.clearTimeout(timeout); window.removeEventListener("message", receiveAck); resolve(); } function receiveAck(event) { if ( event.origin === signCustomiserOrigin && event.source === iframe.contentWindow && event.data?.type === "sc:cart:result:ack" && event.data.checkoutAttemptId === checkoutAttemptId ) { finish(); } } window.addEventListener("message", receiveAck); iframe.contentWindow?.postMessage( { type: "sc:cart:result", checkoutAttemptId, ...result, }, signCustomiserOrigin, ); });}6. Handle the product-created event
Add this case to the validated message listener from step 3.
if (event.data?.type === "sc:product:created") { const { checkoutAttemptId } = event.data; try { await addSignCustomiserProduct(event.data); await reportCartResult(checkoutAttemptId, { outcome: "succeeded" }); storefrontCart.open(); } catch (error) { await reportCartResult(checkoutAttemptId, { outcome: "failed", classification: "unknown_failure", }); iframe.contentWindow?.postMessage( { type: "addToCartFailed", errorMessage: "We could not add this product to the cart. Try again.", }, signCustomiserOrigin, ); }}Keep the origin and iframe-window checks from step 3 around this code.
Classify known failures as platform_rejected, platform_unavailable, or cart_unavailable. Use unknown_failure for other failures.
Do not send exception messages or Shopify response bodies in the result message.
7. Test the installation
Complete these checks before you publish the storefront:
-
Open the customiser in each supported market and currency.
-
Confirm that the displayed price uses the correct presentment currency.
-
Create a design and select Add to Cart.
-
Confirm that the generated variant is available to the headless storefront publication.
-
Confirm that the cart contains one generated variant and all line attributes.
-
Complete checkout and open the order in Shopify admin.
-
Confirm that the design details and files are available for production.
If the generated variant is unavailable, check the Publication setting and the active Shopify market first.