Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

UltraCart has the ability to automatically inject Google Analytics (GA4) tracking code into your catalog and checkout screen brandingStoreFront

The following tutorial will walk you through configuring your Google Analytics account information within your UltraCart account.

Storefronts 

...

titleStorefronts

...

  First navigate to:

Panel

Main MenuStorefront → (pop out menu) Storefront host → (Storefront Menu) Conversion Tracking → Google (tab)

For Storefronts Documentation, see: Adding Google Tracking to your web site

StoreFront Conversion and Tracking

Legacy Screen Branding Themes

...

Panel

Main MenuConfigurationScreen Branding Themes[edit]Conversion & Tracking

Now scroll down to the Supported section. This section Now scroll down to the Supported section. This section contains all of the different tracking systems that UltraCart has built in support for.

In this list you will find "Google Analytics Account Number - Default" as shown below.

Image Removed

Enter your "UA-" value into this field.

Tracking Types

There are multiple tracking types supported by UltraCart. The table below describes the various types, the script Google uses, and whether they support asynchronous loading:

Domain Override

  By default the system is using secure.ultracart.com in the checkout then the GA tracking is set to use that host. If you have a custom SSL then secure.yourdomain.com is passed to the tracking script as .yourdomain.com. This field will provide advanced user the ability to override this on the Google analytics tracking script. 

Pricing Tiers

If you have pricing   For the tracking type select GA4.  As of July 1, 2023 all other Google Analytics tracking types beside GA4 have been discontinued by Google.

Image Added

Account Number

Enter the GA4 measurement ID in BOTH the "Account Number - Default" and "GA4 Measurement ID" field.  This value should look like G-**************.

Obtaining your GA4 Measurement ID

  1. In Admin, make sure that you have the desired account and property selected.
  2. In the Property column, click Data Streams, then click your web data stream. Your “G-” Measurement ID appears in the upper right portion of the panel.
    Image Added

Pricing Tiers

If you have pricing tiers configured on your account for wholesale customers then you can track them on a separate Google Analytics account if you would like. There will be an additional row in the configuration for each pricing tier on your store. If you leave these blank then UltraCart will use the default UA- account when tracking the customer even if they have a pricing tier.

Frequently Asked Questions

Q: I have Google Analytics configured and it's working fine for order placed from the website, but it's not being triggered for my auto orders?

A: The Google Analytic script is fired off based on cookies in the customer browser during the checkout. Since auto orders are generated without the additional involvement from the customer's browser, the GA script is not fired.

The following message from one of our merchants describes an *unofficial* (not directly supported by UltraCart basic support, troubleshooting only available through paid support $100/hr after review by Pro Service department) workaround that they have implemented to triggered the GA script using the XML Postback:

Tip

For the latest and greatest code, please visit this github site:

https://github.com/ryanjkelly/xml2ga

Ryan has made numerous improvements since the initial development which is listed below.

 

 

...

 

Code Block
languagegroovy
titleSample Script
linenumberstrue
collapsetrue
<?php

// ----------------------------------------------- //
//    Generate a unique ID for Google Analytics    //
// ----------------------------------------------- //

function gen_uuid() { // Generates a UUID. A UUID is required for the measurement protocol.
  return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
    // 32 bits for "time_low"
    mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
    // 16 bits for "time_mid"
    mt_rand( 0, 0xffff ),
    // 16 bits for "time_hi_and_version",
    // four most significant bits holds version number 4
    mt_rand( 0, 0x0fff ) | 0x4000,
    // 16 bits, 8 bits for "clk_seq_hi_res",
    // 8 bits for "clk_seq_low",
    // two most significant bits holds zero and one for variant DCE1.1
    mt_rand( 0, 0x3fff ) | 0x8000,
    // 48 bits for "node"
    mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
  );
}


// -------------------- //
//     GA Post Data     //
// -------------------- //

$url = 'https://www.google-analytics.com/collect'; // This is the URL to which we'll be sending the post request.
$user_agent = 'UltraCart/1.0'; // User agent recorded into Google


// ---------------------------------- //
//    Get UltraCart post back data    //
// ---------------------------------- //

// Read in the XML document from the post data
$xml_document = file_get_contents('php://input');

// Parse the XML Document into a DOM Object
$doc = new DOMDocument();
$doc->loadXML($xml_document);

// Extract key fields
$exports = $doc->getElementsByTagName("export");
foreach ($exports as $export) {
	$orders = $export->getElementsByTagName("order");
	
	// Get order element
	foreach($orders as $order) {
		
		// Get order data
		$orderCS = $order->getElementsByTagName("current_stage")->item(0)->nodeValue;           // gets the current stage of the order
		$orderPS = $order->getElementsByTagName("payment_status")->item(0)->nodeValue;          // gets the payment status of the order
		$orderSM = $order->getElementsByTagName("shipping_method")->item(0)->nodeValue;         // gets the shipping method of the order
		$orderTI = $order->getElementsByTagName("order_id")->item(0)->nodeValue;                // gets the transaction ID
		$orderTR = $order->getElementsByTagName("total")->item(0)->nodeValue;                   // gets the transaction revenue
		$orderTS = $order->getElementsByTagName("shipping_handling_total")->item(0)->nodeValue; // gets the transaction shipping
		$orderTT = $order->getElementsByTagName("tax")->item(0)->nodeValue;                     // gets the transaction tax
		$customField1 = $order->getElementsByTagName("custom_field_1")->item(0)->nodeValue;     // gets the product
		$customField2 = $order->getElementsByTagName("custom_field_2")->item(0)->nodeValue;     // gets the product category
		$customField4 = $order->getElementsByTagName("custom_field_4")->item(0)->nodeValue;     // gets the GA client ID
		$customField5 = $order->getElementsByTagName("custom_field_5")->item(0)->nodeValue;     // gets the subid value
		$orderOTI = $order->getElementsByTagName("auto_order_original_order_id")->item(0)->nodeValue; // gets the original transaction ID
		$orderRTR = $order->getElementsByTagName("total_refunded")->item(0)->nodeValue;               // gets the refunded transaction revenue
		$orderRBU = $order->getElementsByTagName("refund_by_user")->item(0)->nodeValue;               // gets the user who processed the refund
		$orderRMN = $order->getElementsByTagName("merchant_notes")->item(0)->nodeValue;               // gets the merchant notes for refund

			// ----------------------------------------- //
			//    POST Order Data to GOOGLE ANALYTICS    //
			// ----------------------------------------- //

			// generate (or pass through) unique ID for GA CID
			if (empty($customField4) || $customField4 == 'undefined') { $orderCID = gen_uuid(); } else { $orderCID = $customField4; }

			$orderData = array( // This is an associative array that will contain all the parameters that we'll send to Google Analytics
			  'v' => 1, // The version of the measurement protocol
			  'tid' => 'UA-######-###', // Google Analytics account ID
			  'cid' => $orderCID, // The client ID or UUID
			  't' => 'transaction' // Hit Type
			);
				
				// ------------------------------------------------------------ //
				//    If order is in 'Completed Order' stage -AND- 'Processed'  //
				//       -AND- not coming from the 'Shipping Department'        //
				//                             -OR-                             //
				//        in the 'Shipping Department' -AND- 'Processed'        //
				// ------------------------------------------------------------ //
				
				if (($orderCS === 'CO' && $orderPS === 'Processed' && empty($orderSM)) || ($orderCS === 'SD' && $orderPS === 'Processed')) {
					$orderData['dh'] = 'secure.ultracart.com'; // Sets the document hostname for GA
					$orderData['dp'] = '/processed'; // Sets the document path for GA
					$orderData['dt'] = 'Order Processed'; // Sets the document title for GA
					$orderData['ti'] = $orderTI; // Sets the transaction ID for GA
					$orderData['tr'] = $orderTR; // Sets the transaction revenue for GA
					$orderData['ts'] = $orderTS; // Sets the transaction shipping for GA
					$orderData['tt'] = $orderTT; // Sets the transaction tax for GA
					$orderData['cd3'] = $customField2; // Sets a custom dimension (Product Category)
					$orderData['cd4'] = $customField5; // Sets a custom dimension (Subid)
				}

				// --------------------------------------------------- //
				//           If order has been refunded from           //
				//    'Completed Orders' -OR- 'Shipping Department'    //
				// --------------------------------------------------- //

				if (($orderCS === 'CO' && $orderPS === 'Refunded') || ($orderCS === 'SD' && $orderPS === 'Refunded')) {
					$orderData['dh'] = 'secure.ultracart.com'; // Sets the document hostname for GA
					$orderData['dp'] = '/refunded'; // Sets the document path for GA
					$orderData['dt'] = 'Order Refunded'; // Sets the document title for GA
					$orderData['ti'] = 'ref-'.$orderOTI; // Sets the transaction ID for GA
					$orderData['tr'] = '-'.$orderRTR; // Sets the transaction revenue for GA
					$orderData['cd11'] = $orderRBU; // Sets a custom dimension (Refund by User)
					$orderData['cd5'] = $orderRMN; // Sets a custom dimension (Merchant Notes)
					$orderData['cd3'] = $customField2; // Sets a custom dimension (Product Category)
					$orderData['cd4'] = $customField5; // Sets a custom dimension (Subid)
				}

			$orderContent = http_build_query($orderData); // The body of the post must include exactly 1 URI encoded payload and must be no longer than 8192 bytes. See http_build_query.
			$orderContent = utf8_encode($orderContent); // The payload must be UTF-8 encoded.

			$orderCH = curl_init();
			curl_setopt($orderCH,CURLOPT_USERAGENT, $user_agent);
			curl_setopt($orderCH,CURLOPT_URL, $url);
			curl_setopt($orderCH,CURLOPT_HTTPHEADER,array('Content-type: application/x-www-form-urlencoded'));
			curl_setopt($orderCH,CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
			curl_setopt($orderCH,CURLOPT_POST, TRUE);
			curl_setopt($orderCH,CURLOPT_POSTFIELDS, $orderContent);
			curl_exec($orderCH);
			curl_close($orderCH);

	} // END foreach($orders as $order)

		// Get item element/s
		$items = $order->getElementsByTagName("item");
		$i = 0; // set increment number
		foreach($items as $item) {

			// Get item data
			$itemIN = $item->getElementsByTagName("item_id")->item(0)->nodeValue;                  // gets the item name
			$itemIP = $item->getElementsByTagName("total_cost_with_discount")->item(0)->nodeValue; // gets the item price
			$itemIQ = $item->getElementsByTagName("quantity")->item(0)->nodeValue;                 // gets the item quantity
			
			// ------------------------------------------------------------ //
			//    If order is in 'Completed Order' stage -AND- 'Processed'  //
			//       -AND- not coming from the 'Shipping Department'        //
			//                             -OR-                             //
			//        in the 'Shipping Department' -AND- 'Processed'        //
			// ------------------------------------------------------------ //
			
			if (($orderCS === 'CO' && $orderPS === 'Processed' && empty($orderSM)) || ($orderCS === 'SD' && $orderPS === 'Processed')) { 

			// ---------------------------------------- //
			//    POST Item Data to GOOGLE ANALYTICS    //
			// ---------------------------------------- //

			$i++; // increase number for each $item
			$itemData = 'itemData'.$i; // append increment number to $itemData variable
			$itemContent = 'itemContent'.$i; // append increment number to $itemContent variable
			$itemCH = 'itemCH'.$i; // append increment number to $itemContent variable
			$itemCID = 'itemCID'.$i; // append increment number to $itemCID variable

			${$itemCID} = $orderCID; // use $orderCID as the GA CID

			${$itemData} = array( // This is an associative array that will contain all the parameters that we'll send to Google Analytics
			  'v' => 1, // The version of the measurement protocol
			  'tid' => 'UA-######-###', // Google Analytics account ID
			  'cid' => ${$itemCID}, // The client ID or UUID
			  't' => 'item' // Hit Type
			);

			${$itemData}['ti'] = $orderTI; // Sets the transaction ID for GA
			${$itemData}['in'] = $itemIN; // Sets the item name for GA
			${$itemData}['ip'] = $itemIP; // Sets the item price for GA
			${$itemData}['iq'] = $itemIQ; // Sets the item quantity for GA
			${$itemData}['cd3'] = $customField2; // Sets a custom dimension (Product Category)
			${$itemData}['cd4'] = $customField5; // Sets a custom dimension (Subid)

			${$itemContent} = http_build_query(${$itemData}); // The body of the post must include exactly 1 URI encoded payload and must be no longer than 8192 bytes. See http_build_query.
			${$itemContent} = utf8_encode(${$itemContent}); // The payload must be UTF-8 encoded.

			${$itemCH} = curl_init();
			curl_setopt(${$itemCH},CURLOPT_USERAGENT, $user_agent);
			curl_setopt(${$itemCH},CURLOPT_URL, $url);
			curl_setopt(${$itemCH},CURLOPT_HTTPHEADER,array('Content-type: application/x-www-form-urlencoded'));
			curl_setopt(${$itemCH},CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
			curl_setopt(${$itemCH},CURLOPT_POST, TRUE);
			curl_setopt(${$itemCH},CURLOPT_POSTFIELDS, ${$itemContent});
			curl_exec(${$itemCH});
			curl_close(${$itemCH});
			
			} // END IF ORDER IS COMPLETED/SHIPPING AND PROCESSED

		} // END foreach($items as $item)
			
} // END foreach ($exports as $export)



// BEGIN $order/$export
foreach ($exports as $export) { foreach($orders as $order) {

	// ---------------------------------------------- //
	//    POST #1 to GOOGLE ANALYTICS (Event Data)    //
	// ---------------------------------------------- //

// ------------------------------------------------------------ //
//    If order is in 'Completed Order' stage -AND- 'Processed'  //
//       -AND- not coming from the 'Shipping Department'        //
//                             -OR-                             //
//        in the 'Shipping Department' -AND- 'Processed'        //
// ------------------------------------------------------------ //

if (($orderCS === 'CO' && $orderPS === 'Processed' && empty($orderSM)) || ($orderCS === 'SD' && $orderPS === 'Processed')) { 

	$data1 = array( // This is an associative array that will contain all the parameters that we'll send to Google Analytics
	  'v' => 1, // The version of the measurement protocol
	  'tid' => 'UA-######-###', // Google Analytics account ID
	  'cid' => $orderCID, // The client ID or UUID
	  't' => 'event' // Hit Type
	);
	
	$data1['dh'] = 'secure.ultracart.com'; // The GA document host name
	$data1['ec'] = 'Sales'; // The GA event category
	$data1['ea'] = 'Order Processed'; // The GA event action
	$data1['el'] = (isset($orderTI) ? $orderTI : 'No Order ID'); // The GA event label
	$data1['cd3'] = $customField2; // Sets a custom dimension (Product Category)
	$data1['cd4'] = $customField5; // Sets a custom dimension (Subid)
	
	$content1 = http_build_query($data1); // The body of the post must include exactly 1 URI encoded payload and must be no longer than 8192 bytes. See http_build_query.
	$content1 = utf8_encode($content1); // The payload must be UTF-8 encoded.
	
	$ch1 = curl_init();
	curl_setopt($ch1,CURLOPT_USERAGENT, $user_agent);
	curl_setopt($ch1,CURLOPT_URL, $url);
	curl_setopt($ch1,CURLOPT_HTTPHEADER,array('Content-type: application/x-www-form-urlencoded'));
	curl_setopt($ch1,CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
	curl_setopt($ch1,CURLOPT_POST, TRUE);
	curl_setopt($ch1,CURLOPT_POSTFIELDS, $content1);
	curl_exec($ch1);
	curl_close($ch1);
	
} // END IF ORDER IS COMPLETED/SHIPPING AND PROCESSED

}} // END $order/$export


//
// NOTICES
//

foreach ($exports as $export) {
	foreach($orders as $order) {
		// Notice: Order processed and placed into 'Completed Orders'.
		if ($orderCS === 'CO' && $orderPS === 'Processed' && empty($orderSM)) { echo 'Order has been processed and placed into Completed Orders. ID is '.$orderTI.', CID is '.$orderCID.' and total is '.$orderTR.'. '; }
		// Notice: Order processed and placed into 'Shipping Department'.
		if ($orderCS === 'SD' && $orderPS === 'Processed') { echo 'Order has been processed and placed into Shipping Department. ID is '.$orderTI.', CID is '.$orderCID.' and total is '.$orderTR.'. '; }
		// Notice: Duplicate order ignored.
		if ($orderCS === 'CO' && $orderPS === 'Processed' && !empty($orderSM)) { echo 'Order from Shipping Department has been ignored. ID is '.$orderTI.' and total is '.$orderTR.'. '; }
		// Notice: Order refunded from 'Completed Orders'.
		if ($orderCS === 'CO' && $orderPS === 'Refunded') { echo 'Order from Completed Orders has been refunded. ID is '.$orderOTI.' and amount refunded is '.$orderRTR.'. Merchant Notes by '.$orderRBU.': '.$orderRMN.'. '; }
		// Notice: Order refunded from 'Shipping Department'.
		if ($orderCS === 'SD' && $orderPS === 'Refunded') { echo 'Order from shipping department has been refunded. ID is '.$orderOTI.' and amount refunded is '.$orderRTR.'. Merchant Notes by '.$orderRBU.': '.$orderRMN.'. '; }
	}
	foreach($items as $item) {
		// Get item data
		$itemIN = $item->getElementsByTagName("item_id")->item(0)->nodeValue;                  // gets the item name
		$itemIP = $item->getElementsByTagName("total_cost_with_discount")->item(0)->nodeValue; // gets the item price
		$itemIQ = $item->getElementsByTagName("quantity")->item(0)->nodeValue;                 // gets the item quantity
		// Notice: Items ordered.
		if ($orderCS === 'CO' && $orderPS === 'Processed' && empty($orderSM) || $orderCS === 'SD' && $orderPS === 'Processed') {echo 'Ordered '.$itemIQ.' of '.$itemIN.' for '.$itemIP.' each. ';}
	} 
}

?>

Q: How do I support Google Analytics Display Network Tracking?

A: UltraCart supports Google Analytics Display Network tracking (DoubleClick.net) already. In the Tracking Type drop down select "Display Network".  This will automatically change the tracking code snippet to conform with Google's document Update Your Analytics Tracking Code to Support Display Advertising.

Q: Which "tracking Types" is the Universal Analytics?

A: Choose "E-Commerce" from the tracking type drop-down menu, which corresponds to the Universal Analytics (UA) with the e-commerce plugin.

Q: Are there any tools for testing my google analytics?

A: The Google Analytics Debugger tool can be used to test and troubleshoot your google analytics configuration.
https://chrome.google.com/webstore/detail/google-analytics-debugger/jnkmfdileelhofjcijamephohjechhna?hl=en 

Q: How do I configure goals and funnels tracking?

...

Info
titleAdvanced Google Analytics Consultation

If you are having trouble with Google Analytics tracking traffic from your sites end-to-end through the checkout then we recommend hiring a consultant to assist you with the proper site linking and conversion code. 

https://www.ultracart.com/resources/partners/seo_and_analytics/tribal_core/

https://www.ultracart.com/resources/partners/seo_and_analytics/tech-guys-who-get-marketing/

Related Resources

Introduction to Google Analytics in UltraCart

Custom Google Analytics Conversion Pixel

...

Domain Override

By default the system is using MerchantID.ultracartstore.com at the host to the checkout then the GA tracking is set to use that host. If you have a custom SSL then secure.yourdomain.com is passed to the tracking script as .yourdomain.com. This field will provide advanced user the ability to override this on the Google analytics tracking script. 

Info
titlePro Tip - Use Custom SSL

Given that cookies are used to track the checkout progress, it's best if you use a custom SSL so that your checkout and website are on the same root domain.

So for example you would have:

www.yourdomain.com -> MID.yourdomain.com

Then in your GTM or GA tracking you would set the allow domain to ".yourdomain.com". This will allow the GA tracking cookies to be visible on both domains.

If you have two different root domains then on your www.yourdomain.com you're going to have to implement some of the techniques documented on this page.

https://support.google.com/analytics/answer/1034342?hl=en

Cross Domains

If you need cross domain tracking in Google Analytics, enter a comma separated list of domains here. Do not add any spaces.

Example: mydomain.com,another.domain.com

Opt Into

Use the "Opt in to" setting to assign (Drop-down list: Statistics / Preferences / Marketing) required for (Drop-down list: All Customers / EEA Customers / Non-US Customers)

GA4 API Secret

If you want UltraCart to use the Google Measurement API to report offline conversions (such as when the upsell closer finalizes an order) or auto order rebills, configure the GA4 API Secret field.

Obtaining your GA4 API Secret

  1. First, go to your Google Analytics Admin > Data Streams and open your chosen stream:
    Image Added
  2. Scroll down to the Additional Settings tab and click on Measurement Protocol API secrets; then click Create:
    Image Added
    Image Added
  3. You will have to create a nickname for your new API secret; we recommend naming this GA4-key. Click Create
  4. You will need to copy the Secret value provided into the corresponding UltraCart configuration field. 
    This value is confidential and should only be configured in your UltraCart account.
  5. All done!

GA4 Server Container URL

If you are running your own GA4 server side tracking instance, configure the URL here. UltraCart will pass this to the gtag config as an option. If you don't know what this means, do not configure anything.

GA4 User ID (Provide UC Analytics ID as User ID)

Select this checkbox if you to provide UC Analytics ID as the user ID.

Info
This setting allows the collection of UltraCart Analytics ID in the data that Google Analytics can push into Google Big Query for enhanced analytic tracking data.

Supported GA4 Events for all Themes

EventWhat triggers the event
page_viewWhen a page is viewed in the StoreFront or checkout
purchaseWhen a purchase occurs and the customer views the receipt.  If the customer abandons the upsell sequence and the order is generated by the upsell closer, then those purchase events are reported through the Google Measurement protocol if the GA4 API key is configured.

Supported GA4 Events in StoreFront Visual Builder Themes

EventWhat triggers the event

add_payment_info

When the credit card number field is populated during the checkout.

add_shipping_info

When a shipping method is selected during the checkout

add_to_cart

When a customer adds an item to the cart

add_to_wishlist

When a customer adds an item to their wishlist

begin_checkout

When the customer begins filling out inputs in the checkout form or interacts with an alternate payment method such as PayPal, Apple Pay or Google Pay

login

When the customer logs into their customer profile during the checkout or in the MyAccount area.

remove_from_cart

When the customer removes an item from their cart by setting the quantity to zero or clicking a remove button.

search

When the customer enters a search phrase

select_promotion

When the customer accepts an upsell after offer.

signup

When the customer registers for a profile during the checkout or through the MyAccount signup form.

view_cart

When the customer views the item's in their cart during the checkout

view_item

When the customer views a specific item within a StoreFornt

view_item_list

When the customer views a list of items.  This can include related items in the checkout, a group of items, search results, etc.
view_promotionWhen the customer views an upsell after offer.


Note
titleNon-Visual Builder Themes

Non-Visual Builder themes do not have built in support for the events above.  Those themes include: Mr Teas, Craft, Natural, Woodland, Gridzy, Fashion and Coffee.

Supported GA4 Events when the GA4 API is Configured

EventWhat triggers the event
earn_virtual_currencyWhen a customer earns a cashback award through the Loyalty Program
purchaseWhen a purchase occurs offline (i.e the csutomer does not see the receipt because the order is created by the upsell closer or a subscription rebill)
refundWhen a refund occurs on an order.  Since this is an offline operation, it can only be reported through the GA4 API.
spend_virtual_currencyWhen a customer redeems a cashback award through the Loyalty Program

Frequently Asked Questions

Q: If I use the GA4 measurement API, will the events associate with the GA4 session?

A: Yes, UltraCart captures the session ID out of the _ga_<container id> cookie on the browser and uses that value when passing Google Measurement events.  This can be observed in the integration logs for the Google Measurement integration.

Q: Can I track a GA4 session across multiple domains like www.mydomain.com and secure.mydomain.com

A: Yes, make sure that you configure GA4 for cross domain functionality.  Also we recommend deploying UltraCart Analytics to your external site so that UltraCart can observe the entire session end-to-end and collect necessary identifiers to drive the Google Measurement API.