Before getting into the details of the post… Happy New Year to all of you! I hope that 2016 is full of DMPs, DTMs and Analytics 🙂

Now, going back to today’s topic, I want to talk about how to create the products string in DTM using the W3C data layer. One of the reasons why we prefer a tag management solution (TMS) over hard-coded snippets is to write less code. All modern TMSs include features to set analytics variables using a point and click interface, usually through Web. In the case of DTM, you can create a data element that reads a data layer variable; you can then assign it to an eVar or a prop, without writing a single line of code.

However, when it comes to the products string, things are not that easy. There is no simple way of creating a one-size-fits-all solution for this variable. Let’s have a quick reminder of this variable’s structure:

"Category;Product;Quantity;Price;eventN=X[|eventN2=X2];eVarN=merch_category[|eVarN2=merch_category2]" 1 "Category;Product;Quantity;Price;eventN=X[|eventN2=X2];eVarN=merch_category[|eVarN2=merch_category2]"

which can be repeated as many times as needed, once for each product, using the comma as separator. Each element in this structure has its own rules:

Category. It is rarely used, as there was a limitation in SiteCatalyst v14 that only allowed one category per product. This limitation was lifted with v15, but very few implementations use it anyway.

Product. This is the only mandatory element.

Quantity. Only on the order confirmation page.

Price. Total price of all units combined for that product; only on the order confirmation page.

Product-specific events. Optional.

Merchandising eVars. Optional and, usually, only on product view or add to basket.

Data Elements for products

As it can be seen, there are many potential combinations of these elements. As a consequence, my recommendation is to create one data element (custom script) in DTM for each of the cases. For example:

Product listing page (PLP)

Product description page (PDP)

Cart page

Add to basket

Remove from basket

Order confirmation page

As an example, on the order confirmation page, you could use code similar to the following:

var products = ''; try { var arrprod = []; for (var i = 0; i < digitalData.transaction.item.length; ++i) { var prod; prod = ';' + digitalData.transaction.item[i].productInfo.productID; prod += ';' + digitalData.transaction.item[i].quantity; prod += ';' + digitalData.transaction.item[i].price.priceWithTax; if (digitalData.transaction.item[i].attributes.isGift) { prod += ";event48=1"; } arrprod.push(prod); } products = arrprod.join(','); } catch (e) { _satellite.notify(e,5); } return products; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var products = '' ; try { var arrprod = [ ] ; for ( var i = 0 ; i < digitalData . transaction . item . length ; ++ i ) { var prod ; prod = ';' + digitalData . transaction . item [ i ] . productInfo . productID ; prod += ';' + digitalData . transaction . item [ i ] . quantity ; prod += ';' + digitalData . transaction . item [ i ] . price . priceWithTax ; if ( digitalData . transaction . item [ i ] . attributes . isGift ) { prod += ";event48=1" ; } arrprod . push ( prod ) ; } products = arrprod . join ( ',' ) ; } catch ( e ) { _satellite . notify ( e , 5 ) ; } return products ;

In this example, if a product is a gift, event48 should also be set.

Remember to use the correct data layer object for each case:

digitalData.product: PDPs and PLPs

digitalData.cart: add to basket event, cart and checkout pages

digitalData.transaction: order confirmation page

I have already described some details about digitalData.product and digitalData.cart in my post The W3C data layer – part II.

Products in rules

As you know, the recommended approach to set Adobe Analytics variables using data elements and is to use directly the UI:

However, the products string and the purchaseID variable cannot be set through the UI. The only option is to set them in code, using something similar to:

s.products = _satellite.getVar("AA:product:order:products"); s.purchaseID = _satellite.getVar("AA:product:order:orderID"); if (s.products.indexOf("event48=") > -1) { s.events = s.apl(s.events,"event48",',',2); } 1 2 3 4 5 s . products = _satellite . getVar ( "AA:product:order:products" ) ; s . purchaseID = _satellite . getVar ( "AA:product:order:orderID" ) ; if ( s . products . indexOf ( "event48=" ) > - 1 ) { s . events = s . apl ( s . events , "event48" , ',' , 2 ) ; }

Please note that the events string must also be updated depending on the product-specific events. Following the previous example, event48 needs to be set only if it is set in the products string. In rules where the Adobe Analytics call is s.tl() , DTM will detect that s.products has been set and will add it to s.linkTrackVars , but not the events in it. Thus, the variable s.linkTrackEvents must also be updated. For example:

s.products = _satellite.getVar("AA:msgbus:addToBasket:products"); if (s.products.indexOf("event12=") > -1) { s.linkTrackEvents = s.apl(s.linkTrackEvents,"event12",',',2); s.events = s.apl(s.events,"event12",',',2); } if (s.products.indexOf("event13=") > -1) { s.linkTrackEvents = s.apl(s.linkTrackEvents,"event13",',',2); s.events = s.apl(s.events,"event13",',',2); } 1 2 3 4 5 6 7 8 9 s . products = _satellite . getVar ( "AA:msgbus:addToBasket:products" ) ; if ( s . products . indexOf ( "event12=" ) > - 1 ) { s . linkTrackEvents = s . apl ( s . linkTrackEvents , "event12" , ',' , 2 ) ; s . events = s . apl ( s . events , "event12" , ',' , 2 ) ; } if ( s . products . indexOf ( "event13=" ) > - 1 ) { s . linkTrackEvents = s . apl ( s . linkTrackEvents , "event13" , ',' , 2 ) ; s . events = s . apl ( s . events , "event13" , ',' , 2 ) ; }

Be careful if you use “eventX” without the equals sign (=) in the call to indexOf() , as there is the small risk of setting the wrong event. For example, s.products.indexOf("event12") will detect event12, but also event120–event129.