Shopify

Using Shopify Cart Permalinks with Convert's Custom App

Enhance Shopify Checkout Tracking with Dynamic Cart Attributes for A/B Testing Success

IN THIS ARTICLE YOU WILL:

Overview

Shopify Cart Permalinks allow you to create links that lead directly to a pre-filled cart or checkout page, making it easier for customers to complete their purchases. With Convert's Shopify App, you can now enhance your A/B testing capabilities by appending cart attributes to these permalinks. This ensures that visitor data and experiment information are dynamically passed to the Shopify checkout process.

This guide explains how to implement the functionality using custom JavaScript in your Shopify store. Follow the steps below to dynamically append cart attributes and visitor data to Shopify cart URLs.

Prerequisites

Before proceeding, make sure you have the following:

  1. Convert's Shopify App installed and configured. Learn more about the app here.
  2. A working understanding of how Shopify Cart Permalinks function.

The Code Snippet

Add the following JavaScript code to your Shopify store's Global JavaScript or relevant theme files. This script dynamically appends visitor and experiment data to cart links:

// GlobalJS
(() => {
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => updateCartPermalinks());
    } else {
        updateCartPermalinks();
    }

    function updateCartPermalinks() {
        const visitorData = window.convert.getAllVisitorData();
        const revenueGoalId = 'xxx'; // replace with the revenue goal ID
        const currency = 'USD'; // replace with the currency of the store
        const shopifyData = getShopifyData(visitorData, revenue, currency);
        const anchors = Array.from(document.querySelectorAll('a[href]')).filter(anchor => {
            const href = anchor.getAttribute('href');
            return /\/cart\/\d+:\d+/.test(href);
        });
        anchors.forEach((link) => {
            const url = new URL(link.href, location.href);
            visitorData.bucketing.forEach(({
                experienceId,
                variationId
            }) => {
                if (!url.searchParams.has(`experience_${experienceId}`))
                    url.searchParams.append(`attributes[experience_${experienceId}]`, variationId);
            });
            if (!url.searchParams.has("__data"))
                url.searchParams.append("attributes[__data]", shopifyData);
            link.href = url.toString();
        });
    }

    function findAllowedCookieHost(domains, currentHost) {
        let cookieDomain;
        if (domains.find(({
                tld
            }) => tld === currentHost))
            return (cookieDomain = `.${currentHost}`);
        for (const {
                tld,
                hosts
            }
            of domains) {
            if (
                hosts.find(
                    (host) => host.includes(currentHost) || matchWildcard(currentHost, host)
                )
            ) {
                cookieDomain = `.${tld}`;
                break;
            }
        }
        if (cookieDomain) return cookieDomain;
        else return false;

        function matchWildcard(toMatch, wildcard) {
            const regex = new RegExp(
                `^${wildcard
               .replace(/\./g, '\\.')
               .replace(/\?/g, '\\?')
               .split('*')
               .join('.*?')}$`
            );
            return regex.test(`www.${toMatch}`) || regex.test(toMatch);
        }
    }

    function getShopifyData(visitorData, revenueGoalId, currency) {
        const configExperiences = {};
        for (const {
                id,
                type
            }
            of window.convert.data.experiences)
            configExperiences[id] = type;
        const currentHost = window.location.hostname.replace(/^www\./, '');
        return btoa(JSON.stringify({
            accountId: window.convert.data.accountId,
            projectId: window.convert.data.projectId,
            revenueGoalId,
            visitorData,
            configExperiences,
            currency,
            domain: findAllowedCookieHost(window.convert.data.project.domains, currentHost),
            userAgent: window.navigator?.userAgent,
            location: window.document?.location?.href,
            referrer: window.document?.referrer ?? '',
        }));
    }
})();

Explanation of the Code

The JavaScript snippet above performs the following tasks:

  1. Retrieve Visitor Data:
    The script uses window.convert.getAllVisitorData() to fetch all visitor and bucketing information for ongoing experiments.

  2. Identify Cart Links:
    It searches for <a> elements in the DOM whose href attributes match the Shopify Cart Permalink pattern (/cart/{product_id}:{quantity}).

  3. Append Experiment and Visitor Data:

    • Experiment and variation IDs are appended to the cart links as query parameters (e.g., attributes[experience_123] and attributes[variation_456]).
    • Encoded visitor data is added via the __data parameter for more detailed tracking.
  4. Ensure Compatibility with Cookie Domains:
    The script determines the appropriate cookie domain to ensure proper tracking across different subdomains or hosts.

  5. Encode Shopify Data:
    All relevant information, such as visitor data, experiment configuration, and domain details, is base64-encoded for compact and secure transmission.