Javascript Variables

This won’t be a lesson in Javascript (though I may have one in the works for future series), but I will touch on a couple data types in examples for accessing those. As covered in the Basics of Browser and Connections post, Javascript lives along-side the rest of the data sources that follow. Javascript variables will be the [“kind of”static] data that is created by the Framework of the site. This gives us the “safety net” of being managed by some kind of Standards, and/or being maintained by the development group. For this reason, this should be our primary data mapping strategy. But there is some complexity that comes along with the infinite – and sometimes recursive – depth that the Javascript space can have. When a Framework, or some notion of a “Data Object/Layer” is present, this complexity reduces dramatically.

The first thing to know when accessing Javascript Variables is the usage of “Javascript Object Notation” ( JSON.org has a great visual), as well as a bit more practical “Property Accessors” which MSDN has a great guide. I’ll try and cover a few of these in the following examples.

“Global” variables, or variables on the document scope, can be referenced directly by name: myVariable.

To pull the value of “myVariable”, we simply reference it with myVariable within a Javascript-enabled mapping field in your tool (like a TMS), or directly in your Javascript code:

The above is the same as saying:

configuration = { "variable1" : "Some Value" }

And is generally part of passing something dynamic like product name, page name, customer info, etc.

So that is a very simple example… and it rarely is so simple. Most often you are going to be working with a Nested structure. Meaning you might have a top-level variable called dataLayer (or utag_data, page_data, etc., from various TMS’s), and depending on the TMS or Framework, you will have levels of variables inside.

Example Tealium Data Layer (or UDO):

var utag_data = {
   page_name: "my page",
   page_type: "landing page",
   page_category: "general"
}

This is pretty simple to work with, as you just need to use “Dot Notation” to reference the child variables. Referencing page_name would done using: utag_data.page_name

Those components being: utag_data -and- . -and- page_name

Not complex right? That is the thought process behind using a “flat data structure”. Within Tealium data mappings, you don’t even need to put the utag_data. bit, just the page_name. The TMS simplifies it.

Working with other TMS’s (again, I’m just presenting both, and representing neither), you would likely have more depth, and so would need to use a . to denote each level of the Object.

Example Data Layer:

var dataLayer = {
   page: {
      name: "my page",
      type: "landing page",
      category: "general"
   }
}

In this instance, to reference the Page Name, you would use: dataLayer.page.name

By no means the end of the world… and many Developers/Taxonomy-stickler’s might feel more comfortable with this. But it can be quite deep and introduces the potential for errors with you need to decide between Dot Notation and Bracket Notation *(see the MSDN article above)*. The need for Bracket Notation comes in any time your child variables have a Space, *start* with a Number, or have some Special Characters in them.

Take the following example:

dataLayer = {
   one: "one",
   2: "two",
   "one and two make three": "three",
   "four*five": "20"
}

 

Now granted, it’s weird to have some number like that, but it’s not actually uncommon when you have poor development practices, or oversight on value validation when variable names/indexes are generated pragmatically.

The following would throw errors when you tried to access them with Dot Notation:

dataLayer.2  <== "Uncaught SyntaxError: Unexpected number"
dataLayer.one and two make three  <== "Uncaught SyntaxError: Unexpected identifier"
dataLayer.four*five <== "Uncaught ReferenceError: five is not defined" . (this is because it's trying to do multiplication)

 

The proper way to access these would be with Bracket Notation

dataLayer[2] -or- dataLayer['2'] <== "two"
dataLayer['one and two make three'] <== "three"
dataLayer['four*five'] <== "20"

And you can apply the same for the nested structure too, utilizing a ['...'] for each depth:

dataLayer['page']['name'] <== "my page"

 

[notification type=”alert-success” close=”false” ]Best Practice Tip:
When creating a “Data Layer Spec” for you clients/developers, always be sure to use Lowercasing and Dashes or Underscores instead of spaces[/notification]

You don’t always get the option to dictate a spec, and so you are left manually searching for variables to use. You can try the Trial and Error method in the Console of your browser (Check out this great article on Developer Tools tricks), and begin typing, hoping auto-complete helps. You can combine that with expanding objects as you find them. But as you can see in the illustrative video below (click to view), that can be quite tedious to find what you actually need:

Screenshot of Console Data Discovery of Data

Beyond this tedious method of discovery, there isn’t really a “magic tool” to get us 100%. Tealium does happen to have a Custom “Tealium Tool” that your support person can provide you with, called “DOM Search”, which allows you to search by both variable Name or by Value.

So if I wanted to search for a variable with price in the name, then I can do that, evaluate if the variables look reliable, and then alternatively search for the actual price value I see on the screen.

[row]
[column lg=”4″ md=”4″ sm=”4″ xs=”4″ ]

[/column]
[column lg=”4″ md=”4″ sm=”4″ xs=”4″ ]

[/column]
[column lg=”4″ md=”4″ sm=”4″ xs=”4″ ]

[/column]
[/row]

 

Other tools might exist, or you could even build you own, you just need to do a Recursive Iteration of the windowobject searching for either a Key or Value.

 

Some Additional Tools to consider:

  • DataSlayer – Gives a similar view to the Tealium Data Layer Identifier tool, and has been around a bit longer. Includes views of Analytics tags as well, which is another source of data (though remember that things are more likely to change in here without you knowing)
  • ObservePoint – Also shows Tags that are firing, but Data associated too. Their paid solution allows for scanning of sites, versus just your own browser activity.
  • Wasp Inspector – A tool built by Cardinal Path agency. Gives you tags that are firing, and additional info on who-loads-who, plus the data associated with the calls.
  • HubScan is a competitor to ObservePoint and Wasp, but I’ve only had cursory exposure to their system.

 

 


Practical Example

The first thing we should do is decide on the data points we need. Lets cover a basic starting point (so this post isn’t 30 pages long) like:

  • Where we are
    • Specifically: Page Type, Page Category Name, Page Category ID
  • What we are looking at, aka Product Info
    • Specifically: Product ID, Product Name, Product Price

The first thing we’ll do is try out the results of the Data Layer inspectors: Tealium and DataSlayer. If you know which TMS the site is using, almost every TMS has their own browser extension to help confirm Data Layer, Tags Firing, and other Configurations… use those first, as those are most likely 100% accurate.

Tealium Data Layer Identifier

[row]
[column lg=”6″ md=”6″ sm=”6″ xs=”6″ ]
The Tealium Data Layer Identifier shows the Signal data object present.

One thing to note is this tool does not show the name of the Data Object on the page that was detected, only the Keys within. It also flattens it, and it has a structure like:

tms_page_data.tms_page_info.page_name

So outside of Signal, you would need to use that full value… inside, you can exclude tms_page_data. I’ll write it out in our final list for compatibility with more tools.

The one problem with this is that you’ll notice that page_name.pageID also includes in the value “SPP”, which is the value of pageType, plus a pipe (“|”), so it’s concatenating the two, likely for some Analytics deployment requirement. Based on what we see on the page, this is pageType plus what should be the Product Name. However, we don’t see Product Name within the data detected.

So really, all we got out of this is Page Type. This is where I’ll say that the Tealium Data Identifier is still in Beta, and doesn’t catch everything, and is SPECIFICALLY only looking for the ON-page data layer object, which is different from the Processed data layer, which can have dynamic and server-side set values. This is where using the Signal tool would be more accurate, or leveraging their built-in functions perhaps.

DataSlayer only shows us data being passed to DoubleClick and SiteCatalyst, nothing about the Data Layer object.

So far our potential mappings are:

  • Page Type
    • tms_page_data.tms_page_info.page_name.pageType
    • “SPP”
  • Page Category Name
    • tms_page_data.tms_page_info.page_name.categoryName
    • “Bronzers”
  • Page Category ID
    • tms_page_data.tms_page_info.page_name.categoryID
    • “CAT640”
  • Product ID ==> ???
  • Product Name ==> ???
  • Product Price ==> ???

[/column]
[column lg=”6″ md=”6″ sm=”6″ xs=”6″ ]

{ Click each image below for a larger view }

[/column]
[/row]

 

Tealium DOM Search

We’ll need to do a little of that manual digging now, but at least we got half-way to our data set… though of course for REAL configurations, we’ll want much more than just the 6 data points we are targeting. Before we jump ALL the way into uber-tedious-console-method, lets try the Tealium DOM Search tool. Again, I’m using Tealium’s tools as an example because I’m most familiar with them for everyday usage.

[row]
[column lg=”6″ md=”6″ sm=”6″ xs=”6″ ]

Lets start off with searching for the Product Name, since we can see it on the page, and there really isn’t a super sure way of seeing the Product ID on the page… at least, not in THIS lesson.

We’ll do a Search by Name, for “product name”, and get no results.

Next we’ll try some variations: “product_name” and “productname“, which the later will get us some results. You’ll notice that it shows us a Product Name and a Sub Product Name. This is where knowing how the brand needs to differentiate these, if at all, will be important. You probably want to ask that, and/or figure out other ways to get either… or join them yourselves. The other consideration here is going to be that its referencing “taaz” (we know the SPP part just means product page now), and we don’t know what that is. If that is an internal framework, then great… but if it is instead some 3rd party library/output, then we DO NOT want to use this, as we don’t know how reliable it is. In fact, 5 seconds on google searching for “taaz” results in confirming it is for a 3rd party tool (http://www.taaz.com/).

So the next search would be to search by Value. I don’t use this as my first search because it will often return LOTS of results. Searching for “Bronze Goddess Powder Bronzer” and “Powder Bronzer” give the same results in this instance, because the later is within the former, but often can give wider results. I like to start specific, and then broaden only if I don’t like the results. In this case, again we only have the taaz variable, pageID, and some SiteCatalyst variables. I will use the pageID value for now, and just know I need to strip out the “SPP  | ” portion.

Repeat the same steps for Product ID and Product Price, using the Name and variations, and then the Value. Product ID is pretty easy, but Product Price is tricky, because everything returned is related to SKU’s and varies in value, so that introduces some additional complexity. We’ll need our final solution to account for us changing the options within the product page.

You should get the following:

  • Page Type
    • tms_page_data.tms_page_info.page_name.pageType
    • “SPP”
  • Page Category Name
    • tms_page_data.tms_page_info.page_name.categoryName
    • “Bronzers”
  • Page Category ID
    • tms_page_data.tms_page_info.page_name.categoryID
    • “CAT640”
  • Product ID
    • window.PRODUCT_ID
    • “PROD25326”
  • Product Name
    • window.tms_page_data.tms_page_info.page_name.pageID
    • “SPP | Bronze Goddess Powder Bronzer”
  • Product Price ==> ???

[/column]

[column lg=”6″ md=”6″ sm=”6″ xs=”6″ ]

{ Click each image below for a larger view }

 

[/column]

[/row]

 

The “Manual” Way

Ok, so now it’s time for the “fun”. We’ll have to try some common searches in the console to see what we can see. You could probably compile a generic list to cover most generic data sets, and then one for each Industry, as they’ll have their own conventions. The 3 most common – and it covers a surprisingly large majority – are:

[row]
[column lg=”6″ md=”6″ sm=”6″ xs=”6″ ]

  1. data, and variations like: datalayer and data_layer
  2. page, and variations like: pagedata and page_data
  3. user, and variations like: userinfo, user_info, customer, customerinfo, customer_info

We get some interesting results. Most specifically when we did page_data, we get an object that has quite a bit of  Product information.

  1. Product ID, without the “PROD” in it can be seen at: page_data.catalog-spp.product[0].PROD_BASE_ID
    1. Remember to use Bracket Notation because of the “0” index
  2. PROD_RGN_NAME and PROD_RGN_SUBHEADING suggest that “Bronze Goddess” is the Product Name, and SubHeading is for display, but at minimum we can combine these two cleanly vs. stripping things out of the pageID
  3. priceRange shows us the individual price (though you might want some logic to take Lower/Upper/Average of this) for the main SKU
  4. and skus contains the individual variation values (you’ll need this after you detect which is currently selected).

 

So at this point we should have:

  • Page Type
    • tms_page_data.tms_page_info.page_name.pageType
    • “SPP”
  • Page Category Name
    • tms_page_data.tms_page_info.page_name.categoryName
    • “Bronzers”
  • Page Category ID
    • tms_page_data.tms_page_info.page_name.categoryID
    • “CAT640”
  • Product ID
    • page_data.catalog-spp.products[0].PROD_BASE_ID
    • “25326”
  • Product Name
    • page_data.catalog-spp.products[0].PROD_RGN_NAME
    • “Bronze Goddess”
  • Product Price
    • page_data.catalog-spp.products[0].priceRange
    • “39.00”

[/column]
[column lg=”6″ md=”6″ sm=”6″ xs=”6″ ]

{ Click each image below for a larger view }

[thumbnail link=”http://localhost:8000/resources/Screen-Shot-2017-04-18-at-6.34.29-PM.png” target=”_blank” src=”http://localhost:8000/resources/Screen-Shot-2017-04-18-at-6.34.29-PM.png”]


[/column]
[/row]

 

Let’s Clean it up

Now that we have the start of our data set, we need to manipulate some of the values. Below are also some handy reusable snippets for many occasions.

Page Category ID
We need to remove the “CAT” portion of this value. To do that we will leverage a simple replace function. You pass it the part you want to search for (aka the Needle in the haystack), and then what to replace it with.

tms_page_data.tms_page_info.page_name.categoryID.replace("CAT", "");

 Here we just replace it with an empty set of quotes or “nothing“. The one catch here is it only replaces the FIRST instance of the needle. If you have many to replace, use this snippet below, but be VERY careful about RegularExpressions, and don’t break any of the special characters.

// Replace ALL instances of "CAT"
tms_page_data.tms_page_info.page_name.categoryID.replace(/(CAT|DOG|SHEEP)/gi,"")

// Replace ALL instances of ANY of "CAT", "DOG", or "SHEEP"
tms_page_data.tms_page_info.page_name.categoryID.replace(/(CAT|DOG|SHEEP)/gi,"")

Product Name
IF we need to combine the Name and SubHeading, we can do that with this snippet… note we are adding a blank space between, you can change that to anything you want within the quotes:

page_data['catalog-spp'].products[0].PROD_RGN_NAME + " " + page_data['catalog-spp'].products[0].PROD_RGN_SUBHEADING

Product Price
IF we want to do some manipulation on this, you can use the following:

First, replace the “$”:

page_data['catalog-spp'].products[0].priceRange.replace(/(\$)/gi,"")

Convert to a NUMBER instead of a STRING representing a number (make sure to check with your TMS which you should use):

Number( page_data['catalog-spp'].products[0].priceRange.replace("$","") )

Take a portion of a range, ASSUMING there is some kind of delimiter:

// Lower or Left side of Delimiter (assuming "-") 
page_data['catalog-spp'].products[0].priceRange.replace(/(\$)/gi,"").split("-")[0]

// Upper or Right side of Delimiter (assuming "-") 
page_data['catalog-spp'].products[0].priceRange.replace(/(\$)/gi,"").split("-")[1]

// Average of range with Delimiter (assuming "-") 
(function(){ 
   var range = page_data['catalog-spp'].products[0].priceRange.replace(/(\$)/gi,"");
   var parts = range.split("-");
   var low = Number(parts[0]);
   if (range.indexOf("-")<0) return low;
   var high = Number(parts[1]);
   return ((low + high)/2);
})()

 

[notification type=”alert-success” close=”false” ]Other Useful Links on Manipulation

  • https://www.w3schools.com/js/js_string_methods.asp
  • https://www.w3schools.com/js/js_math.asp
  • https://www.w3schools.com/js/js_loop_for.asp
  • https://www.sitepoint.com/15-javascript-string-functions/

[/notification]

 

 

That covered quite a bit. Hopefully it flowed logically. Whenever you run into issues, grab a nearby developer, or head over to StackOverflow and ask there. Know of any other tools, I’d love to hear about them. I tried to keep agnostic, but I use these tools daily, so a bit hard not to share since they work well.

Be sure to check out the main post for links to the other posts in this series: Data Mapping Basics – Intro