Integration
This page walks you through integrating your eCommerce store with Shuttlebase. The integration has two steps: granting Google Analytics 4 access and adding the tracking code to your site. Once both are done, Shuttlebase can run and analyze CRO experiments on your store automatically.
Every snippet below contains a <TRACKING_ID> placeholder. Replace it with the unique tracking ID Shuttlebase provides for your account. If Shuttlebase sent you a personalized link to this page, your ID is filled in automatically.
Step 1: Grant Google Analytics (GA4) access
Section titled “Step 1: Grant Google Analytics (GA4) access”- Log in to Google Analytics.
- Choose the GA4 property associated with your eCommerce store from the account list.
- Click the Admin gear icon in the bottom-left corner.
- Under the Account column, click Account Access Management.
- Click the + icon in the top-right corner, then select Add users.
- Enter the email address of Shuttlebase’s technical lead:
evyatar@shuttlebase.com. - Set the permissions to Analyst and click Add to send the invitation.
Step 2: Add the tracking code
Section titled “Step 2: Add the tracking code”The tracking code needs to run on every page of your site. The steps differ by platform, so expand the section that matches yours.
Shopify
Add the tracking code to the end of the <head> section of your theme.liquid file. The code needs to be added as-is, without any additions.
<script src="https://cdn.moonshot-ai.com/snippets/<TRACKING_ID>.js"></script>Revenue tracking on Shopify
Section titled “Revenue tracking on Shopify”Purchases on Shopify are tracked through a custom pixel. These steps cover standard Shopify, not Hydrogen.
- Open the pixel screen. Depending on your Shopify version it is under Settings, then Customer Events, or on older versions under Settings, then Checkout, in the Order status page section.
- Under Custom Pixels, click Add Custom Pixel and name it
MoonshotAI tracking. - Permissions: choose Required and check only Analytics.
- Data Sale: choose “Data collected does not qualify as data sale”.
- Paste the following code and click save.
const REMOTE_LOADER_URL = "https://cdn.moonshot-ai.com/shopify_pixel/shopify_pixel_events_handler.js";const project_id = "<TRACKING_ID>";const __MSAI_PIXEL_DEBUG__ = false;
function loadRemoteScript(url, debug = false) { return new Promise((resolve, reject) => { try { const script = document.createElement("script"); script.src = `${url}`; script.async = true; script.referrerPolicy = "no-referrer"; script.onload = () => { if (debug) { console.log(`[pixel] remote url ${url} loaded`); } resolve(); }; script.onerror = (e) => { if (debug) { console.warn(`[pixel] remote url ${url} failed`, e); } reject(e); }; document.head.appendChild(script); } catch (e) { if (debug) { console.warn(`[pixel] bootstrap error for remote url ${url}`, e); } reject(e); } });}
window.msaiAllowIframe = true;const remoteLoaderPromise = loadRemoteScript(REMOTE_LOADER_URL, __MSAI_PIXEL_DEBUG__);
/** * Flag to track if we've already set up the remote handler properties. * @type {boolean} */let remoteHandlerInitialized = false;
/** * Initializes the remote handler with project-specific properties. * This only runs once to avoid setting up the properties multiple times. */function initializeRemoteHandler() { if (remoteHandlerInitialized) return;
window.__PIXEL_REMOTE__.projectId = project_id; window.__PIXEL_REMOTE__.loadMsaiClientScript = async () => { await loadRemoteScript(`https://cdn.moonshot-ai.com/snippets/${project_id}.js`, __MSAI_PIXEL_DEBUG__); }; remoteHandlerInitialized = true;}
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms));}
async function processEventWithRetry(event, eventName, maxRetries = 5, initialDelay = 100) { let retries = 0; let delay = initialDelay;
while (retries <= maxRetries) { if (window.__PIXEL_REMOTE__ && typeof window.__PIXEL_REMOTE__.handleEvent === "function") { initializeRemoteHandler(); window.__PIXEL_REMOTE__.handleEvent(event); return true; } else { if (retries === maxRetries) { __MSAI_PIXEL_DEBUG__ && console.warn(`[pixel] remote handler not available after ${maxRetries} retries. Event dropped:`, eventName); return false; }
__MSAI_PIXEL_DEBUG__ && console.log(`[pixel] waiting for remote handler to be available. Retry ${retries + 1}/${maxRetries}`); await sleep(delay); delay *= 2; retries++; } }
return false;}
async function subscribeToEvents() { try { analytics.subscribe("all_events", async (ev) => { try { await remoteLoaderPromise; const success = await processEventWithRetry(ev, ev.name); if (success && __MSAI_PIXEL_DEBUG__) { console.log(`[pixel] successfully processed event: ${ev}`); } } catch (error) { __MSAI_PIXEL_DEBUG__ && console.warn(`[pixel] error processing event: ${ev}`, error); } }); console.log("[pixel] loaded"); } catch (e) { __MSAI_PIXEL_DEBUG__ && console.warn("[pixel] failed to subscribe all events", e); }}
subscribeToEvents();VTEX
- Access your website’s HTML files.
- Locate the
<head>section of your site’s HTML. - Paste the tracking code just before the closing
</head>tag. - Save and upload the changes to your server.
<script src="https://cdn.moonshot-ai.com/snippets/<TRACKING_ID>.js"></script>Revenue tracking on VTEX
Section titled “Revenue tracking on VTEX”Add a handleEvents function that listens for the vtex:orderPlaced event, and have it send the revenue event below with the order’s transaction parameters filled in.
Shuttlebase tracks purchases through a revenue event pushed to the snippet’s queue. Replace the {placeholder} values with the actual transaction parameters from the completed order. The comments mark which fields are required.
window['msaiClient'] = window['msaiClient'] || [];window['msaiClient'].push({ event_type: 'revenue', // (REQUIRED) event_value: 123.45, // (REQUIRED) number - The decimal money amount transaction_currency: "{currency}", // (REQUIRED) string - 3-letter ISO 4217 currency code (i.e. USD, EUR, GBP) order_id: "{order_id}", // (REQUIRED) string - Unique order identifier transaction_id: "{transaction_id}", // (OPTIONAL) string | null - Unique transaction identifier discount_allocations: [ // (OPTIONAL) Array of Discounts applied to the entire cart and/or shipping. NOTE if targeting specific products, use the discount_allocations array in the line_items_info to target those specific products. { amount: { // (REQUIRED IF DISCOUNT) The total amount of the discount applied to the entire cart or shipping line amount: {discount_amount}, // number - The decimal money amount currency_code: "USD" // string - 3-letter ISO 4217 currency code (if different from transaction_currency) }, target_type: "{target_type}", // (REQUIRED) string - "LINE_ITEM" for discounts to the entire cart or "SHIPPING_LINE" for discount to entire shipping line title: "{discount_code}", // (REQUIRED IF DISCOUNT CODE) string - The discount code (i.e. "FREESHIP", "CART20") if applicable type: "{type}", // (REQUIRED) string - "AUTOMATIC", "DISCOUNT_CODE" value: { // The discount value amount: {discount_amount}, // (REQUIRED IF FIXED AMOUNT) number - Fixed amount discount (if applicable) currency_code: "USD", // (REQUIRED IF FIXED AMOUNT) string - Currency code for fixed amount (if different from transaction_currency) percentage: 15 // (REQUIRED IF PERCENTAGE) number - Percentage discount (if applicable) } } ], line_items_info: [ // (REQUIRED) Array of detailed information about each item type in the order { id: "{line_item_id}", // (REQUIRED) string - Globally unique identifier (Normally Product ID) quantity: 1, // (REQUIRED) number - Quantity of this item type title: "{product_title}", // (Optional) string - The title of the line item (If different from product title) final_line_price: { // Combined price after line-level discounts amount: 99.99, // (REQUIRED) number - The decimal money amount currency_code: "USD" // (REQUIRED IF DIFFERENT FROM TRANSACTION_CURRENCY) string | null - Only include if the currency is different from the transaction_currency }, variant: { // (REQUIRED) ProductVariant | null - Variant information id: "{variant_id}", // (OPTIONAL) string | null - Globally unique identifier (If not provided, the product_id will be used) title: "{variant_title}", // (OPTIONAL) string | null - The product variant's title (If not provided, the product_title will be used) sku: "{sku}", // (OPTIONAL) string | null - SKU (stock keeping unit) (Can be the product_sku) price: { // (REQUIRED) The product variant's price amount: 99.99, // (REQUIRED) number - The decimal money amount currency_code: "USD" // (REQUIRED IF DIFFERENT FROM TRANSACTION_CURRENCY) string | null - Only include if the currency is different from the transaction_currency }, product: { // (REQUIRED) The product object id: "{product_id}", // (REQUIRED) string | null - The ID of the product title: "{product_title}", // (REQUIRED) string - The product's title type: "{product_type}", // (OPTIONAL) string | null - The product type vendor: "{vendor}", // (OPTIONAL) string - The product's vendor name url: "{product_url}" // (OPTIONAL) string | null - The URL of the product } }, selling_plan_allocation: { // (OPTIONAL) Subscription information selling_plan: { // (OPTIONAL) SellingPlan id: "{selling_plan_id}", // (REQUIRED IF SELLING PLAN) string - Globally unique identifier name: "{selling_plan_name}" // (REQUIRED IF SELLING PLAN) string - Name of the plan (i.e. "6 weeks of prepaid granola, delivered weekly") } }, discount_allocations: [ // (OPTIONAL) Discounts applied to this specific line item { amount: { // (REQUIRED IF DISCOUNT) The monetary value allocated to the discount amount: 5.00, // number - The decimal money amount currency_code: "USD" // string - 3-letter ISO 4217 currency code }, discount_application: { // (REQUIRED IF DISCOUNT) The discount info target_type: "{target_type}", // (REQUIRED) string - "LINE_ITEM" for discounts to the product or "SHIPPING_LINE" for discount to specific product's shipping NOTE: If shipping discount is for all products, use the discount_allocations array in the top level of the event title: "{discount_code}", // (REQUIRED IF DISCOUNT CODE) string - The discount code (i.e. "SAVE20") type: "{type}", // (REQUIRED) string - "AUTOMATIC", "DISCOUNT_CODE" value: { amount: 5.00, // (REQUIRED IF FIXED AMOUNT) number - Fixed amount discount (if applicable) currency_code: "USD", // (REQUIRED IF FIXED AMOUNT) string - Currency code for fixed amount percentage: 10 // (REQUIRED IF PERCENTAGE) number - Percentage discount (if applicable) } } } ] } ]});Other platforms
- Access your website’s HTML files.
- Locate the
<head>section of your site’s HTML. - Paste the tracking code just before the closing
</head>tag. - Save and upload the changes to your server.
<script src="https://cdn.moonshot-ai.com/snippets/<TRACKING_ID>.js"></script>Revenue tracking on other platforms
Section titled “Revenue tracking on other platforms”Find the “thank you for your purchase” page on your site and add the revenue event below, with the transaction parameters filled in from the completed order.
Shuttlebase tracks purchases through a revenue event pushed to the snippet’s queue. Replace the {placeholder} values with the actual transaction parameters from the completed order. The comments mark which fields are required.
window['msaiClient'] = window['msaiClient'] || [];window['msaiClient'].push({ event_type: 'revenue', // (REQUIRED) event_value: 123.45, // (REQUIRED) number - The decimal money amount transaction_currency: "{currency}", // (REQUIRED) string - 3-letter ISO 4217 currency code (i.e. USD, EUR, GBP) order_id: "{order_id}", // (REQUIRED) string - Unique order identifier transaction_id: "{transaction_id}", // (OPTIONAL) string | null - Unique transaction identifier discount_allocations: [ // (OPTIONAL) Array of Discounts applied to the entire cart and/or shipping. NOTE if targeting specific products, use the discount_allocations array in the line_items_info to target those specific products. { amount: { // (REQUIRED IF DISCOUNT) The total amount of the discount applied to the entire cart or shipping line amount: {discount_amount}, // number - The decimal money amount currency_code: "USD" // string - 3-letter ISO 4217 currency code (if different from transaction_currency) }, target_type: "{target_type}", // (REQUIRED) string - "LINE_ITEM" for discounts to the entire cart or "SHIPPING_LINE" for discount to entire shipping line title: "{discount_code}", // (REQUIRED IF DISCOUNT CODE) string - The discount code (i.e. "FREESHIP", "CART20") if applicable type: "{type}", // (REQUIRED) string - "AUTOMATIC", "DISCOUNT_CODE" value: { // The discount value amount: {discount_amount}, // (REQUIRED IF FIXED AMOUNT) number - Fixed amount discount (if applicable) currency_code: "USD", // (REQUIRED IF FIXED AMOUNT) string - Currency code for fixed amount (if different from transaction_currency) percentage: 15 // (REQUIRED IF PERCENTAGE) number - Percentage discount (if applicable) } } ], line_items_info: [ // (REQUIRED) Array of detailed information about each item type in the order { id: "{line_item_id}", // (REQUIRED) string - Globally unique identifier (Normally Product ID) quantity: 1, // (REQUIRED) number - Quantity of this item type title: "{product_title}", // (Optional) string - The title of the line item (If different from product title) final_line_price: { // Combined price after line-level discounts amount: 99.99, // (REQUIRED) number - The decimal money amount currency_code: "USD" // (REQUIRED IF DIFFERENT FROM TRANSACTION_CURRENCY) string | null - Only include if the currency is different from the transaction_currency }, variant: { // (REQUIRED) ProductVariant | null - Variant information id: "{variant_id}", // (OPTIONAL) string | null - Globally unique identifier (If not provided, the product_id will be used) title: "{variant_title}", // (OPTIONAL) string | null - The product variant's title (If not provided, the product_title will be used) sku: "{sku}", // (OPTIONAL) string | null - SKU (stock keeping unit) (Can be the product_sku) price: { // (REQUIRED) The product variant's price amount: 99.99, // (REQUIRED) number - The decimal money amount currency_code: "USD" // (REQUIRED IF DIFFERENT FROM TRANSACTION_CURRENCY) string | null - Only include if the currency is different from the transaction_currency }, product: { // (REQUIRED) The product object id: "{product_id}", // (REQUIRED) string | null - The ID of the product title: "{product_title}", // (REQUIRED) string - The product's title type: "{product_type}", // (OPTIONAL) string | null - The product type vendor: "{vendor}", // (OPTIONAL) string - The product's vendor name url: "{product_url}" // (OPTIONAL) string | null - The URL of the product } }, selling_plan_allocation: { // (OPTIONAL) Subscription information selling_plan: { // (OPTIONAL) SellingPlan id: "{selling_plan_id}", // (REQUIRED IF SELLING PLAN) string - Globally unique identifier name: "{selling_plan_name}" // (REQUIRED IF SELLING PLAN) string - Name of the plan (i.e. "6 weeks of prepaid granola, delivered weekly") } }, discount_allocations: [ // (OPTIONAL) Discounts applied to this specific line item { amount: { // (REQUIRED IF DISCOUNT) The monetary value allocated to the discount amount: 5.00, // number - The decimal money amount currency_code: "USD" // string - 3-letter ISO 4217 currency code }, discount_application: { // (REQUIRED IF DISCOUNT) The discount info target_type: "{target_type}", // (REQUIRED) string - "LINE_ITEM" for discounts to the product or "SHIPPING_LINE" for discount to specific product's shipping NOTE: If shipping discount is for all products, use the discount_allocations array in the top level of the event title: "{discount_code}", // (REQUIRED IF DISCOUNT CODE) string - The discount code (i.e. "SAVE20") type: "{type}", // (REQUIRED) string - "AUTOMATIC", "DISCOUNT_CODE" value: { amount: 5.00, // (REQUIRED IF FIXED AMOUNT) number - Fixed amount discount (if applicable) currency_code: "USD", // (REQUIRED IF FIXED AMOUNT) string - Currency code for fixed amount percentage: 10 // (REQUIRED IF PERCENTAGE) number - Percentage discount (if applicable) } } } ] } ]});After integration
Section titled “After integration”- Tracking snippet covers performance, batching, and load behavior.
- Events lists everything the snippet collects, including custom events you can send through
window.msaiClient. - Cookies and storage lists exactly what the snippet stores in the browser.
- Privacy and consent explains consent modes and CMP integrations.
- Dashboard overview shows where your data appears.
- Third-party integrations lists the tools Shuttlebase connects to.