Integrating Convert.com with Shopify Custom Storefronts and Cross-Origin Checkout
How to Track Conversions in Shopify Custom Storefronts and Cross-Origin Checkouts with Convert.com
IN THIS ARTICLE YOU WILL:
- Understand When Manual Integration is Required
- Use the Helper Function to Update Cart Attributes
- Integrate Convert.com with a Custom Storefront (Shopify Hydrogen, WooCommerce, etc.)
- Track Conversions for a Checkout Page on a Different Domain
Overview
Convert.com’s Shopify App is built to work seamlessly with Liquid-based themes where the storefront and checkout page reside on the same domain.
However, if you're using a custom storefront (e.g., Shopify Hydrogen, WooCommerce) or if your checkout page is hosted on a different domain, you must manually configure tracking.
To enable Convert tracking in these advanced setups, follow the instructions below.
When is Manual Integration Required?
You need to manually integrate Convert’s tracking script if:
✔ You are using a custom storefront (e.g., Shopify Hydrogen, WooCommerce).
✔ Your Shopify checkout page is hosted on a different domain than the storefront.
In such cases, the following actions are necessary:
-
Install the Convert tracking script into the
<head>
tag of the storefront. -
Use the helper function to generate cart attributes and update storage/cart manually.
Helper Function for Updating Cart Attributes
The following JavaScript function retrieves visitor data from Convert and formats it for Shopify’s cart attributes.
/ Helper function for returning Convert Cart Attribute (only works at client-side code)
function getConvertCartAttribute({
revenueGoalId,
subscriptionGoalId, // optional
oneTimePaymentGoalId, // optional
currency,
}) {
const segments = convert.getDefaultSegments();
if (segments) convert.setCookie("_conv_g", JSON.stringify(segments));
const visitorData = convert.getAllVisitorData();
const shopifyData = getShopifyData();
if (!shopifyData) return;
const attributes = { __data: shopifyData };
for (const { experienceId, variationId } of visitorData.bucketing)
attributes[`experience_${experienceId}`] = variationId;
return attributes;
function getShopifyData() {
const experiences = visitorData.bucketing
.filter(
({ experienceId }) =>
!!convert.data.experiences.find(
({ id, type }) => id === experienceId && type !== "deploy"
)
)
.map(({ experienceId }) => String(experienceId));
const domain = getCookieDomain(
convert.data.project.domains,
location.hostname.replace(/^www\./, "")
);
const verifyData = {
experiences,
domain,
};
convert.setCookie("_conv_d", JSON.stringify(verifyData));
return btoa(
JSON.stringify({
accountId: convert.data.account_id,
projectId: convert.data.project.id,
revenueGoalId,
subscriptionGoalId,
oneTimePaymentGoalId,
visitorData,
currency,
experiences,
domain,
})
);
}
function getCookieDomain(domains, currentHost) {
let cookieDomain = "";
if (domains.find(({ tld }) => tld === currentHost))
return `.${currentHost}`;
for (const { tld, hosts } of domains) {
if (
hosts.find(
(host) =>
host.includes(currentHost) || matchWildcard(currentHost, host)
)
) {
cookieDomain = `.${tld}`;
break;
}
}
return cookieDomain;
function matchWildcard(toMatch, wildcard) {
const regex = new RegExp(
`^${wildcard
.replace(/\./g, "\\.")
.replace(/\?/g, "\\?")
.split("*")
.join(".*?")}$`
);
return regex.test(`www.${toMatch}`) || regex.test(toMatch);
}
}
}
Types Appendix: Shopify Data and Cart Attribute Format
// Storage Data
interface ShopifyData {
accountId: string;
projectId: string;
revenueGoalId: string;
subscriptionGoalId?: string;
oneTimePaymentGoalId?: string;
visitorData: VisitorData;
currency: string;
experiences?: string[];
domain?: string;
}
// Cart Attributes
interface ConvertCartAttributes {
__data: string;
[key: string]: string;
}
Case 1: Custom Storefronts (Shopify Hydrogen, WooCommerce, etc.)
If you’re using a custom storefront, you must manually update Shopify’s storage data and cart attributes using the helper function.
Steps to Implement
-
Generate Convert Cart Attributes
// Add an event listener once our tracking script has done processing all goals
_conv_q.push({
what: "addListener",
params: {
event: "snippet.goals_evaluated",
handler: () => {
// Prepare the critical data required by the web pixel in our Shopify App
const attributes = getConvertCartAttribute({
revenueGoalId: "xxxxxxxxx", // replace with the revenue goal ID (required to setup Shopify Order Webhook)
subscriptionGoalId: "", // optional - replace with the subscription goal ID (to setup Shopify Order Webhook)
oneTimePaymentGoalId: "", // optional - replace with the non-subscription goal ID (to setup Shopify Order Webhook)
currency: "xxx", // replace with the target currency when tracking revenue
});
// Optionally setup Shopify Order Webhook
if (typeof updateShopifyCartAttributes === "function")
updateShopifyCartAttributes(attributes);
},
},
});
- Update Shopify Cart Attributes (Optional) This is needed for the Shopify Order Webhook to work correctly.
// Helper function for updating the Shopify cart attributes
function updateShopifyCartAttributes(attributes) {
if (typeof window?.Shopify === "undefined") {
console.warn(
"Convert: This store does not use a standard Shopify theme, skipping Shopify cart update..."
);
return;
}
/**
* IMPORTANT: This function is only applicable for Shopify themes: https://shopify.dev/docs/storefronts/themes
* It does not work with Hydrogen or Webflow. Because they don't have the cart/update.js endpoint.
* Alternatives:
* Hydrogen: https://shopify.dev/docs/storefronts/headless/hydrogen/cart/attributes
* Webflow: N/A
*/
fetch(`${window?.Shopify?.routes || "/"}cart/update.js`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(attributes),
})
.then(() => console.log("Convert: Cart attributes successfully updated"))
.catch(({ message }) =>
console.warn(`Convert: Cart attributes update error: ${message}`)
);
}
Case 2: Checkout Page on a Different Domain
If your checkout page is on a separate domain, you need to update Shopify Cart Permalinks to ensure tracking data is passed to the checkout process.
Steps to Implement
- Modify Cart Permalink URLs This script runs when the page loads and updates cart links dynamically.
(() => {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => updateCartPermalinks());
} else {
updateCartPermalinks();
}
function updateCartPermalinks() {
const attributes = getConvertCartAttribute({
revenueGoalId: 'xxxxxxxxx', // Replace with your revenue goal ID
currency: 'xxx' // Replace with target currency
});
if (!attributes) return;
// Find cart links on the page and update their URLs
const anchors = Array.from(document.querySelectorAll('a[href]')).filter(anchor => /\/cart\/\d+:\d+/.test(anchor.getAttribute('href')));
anchors.forEach((link) => {
const url = new URL(link.href, location.href);
for (const key in attributes)
if (!url.searchParams.has(`attributes[${key}]`))
url.searchParams.append(`attributes[${key}]`, attributes[key]);
link.href = url.toString();
});
}
})();
💡 Important Note:
Using cart permalinks means Convert can only track goals related to the checkout page. Goals such as collection_viewed, product_viewed, and search_submitted cannot be tracked.
If you're using a custom storefront or a cross-origin checkout, Convert tracking requires additional manual integration. By following the steps in this guide, you can ensure Convert continues to track conversion events correctly.
For further assistance, refer to our Shopify Support Articles.