{"id":126866,"date":"2025-03-11T18:46:25","date_gmt":"2025-03-11T18:46:25","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/10-javascript-concepts-for-web-analytics-implementation\/"},"modified":"2025-03-11T18:46:25","modified_gmt":"2025-03-11T18:46:25","slug":"10-javascript-concepts-for-web-analytics-implementation","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=126866","title":{"rendered":"10 JavaScript Concepts For Web Analytics Implementation"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p>I\u2019ve already written <a href=\"https:\/\/www.simoahava.com\/analytics\/javascript-101-gtm-part-1\/\">extensively<\/a> about JavaScript in web analytics implementation. Suffice to say, understanding at least <em>the basics<\/em> is absolutely necessary to survive in the technical medium of the web browser.<\/p>\n<div style=\"aspect-ratio: 2048 \/ 1142;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/10-javascript-concepts.jpg\" title=\"10 JavaScript Concepts for web analytics\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"1142\" width=\"2048\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/10-javascript-concepts.jpg#ZgotmplZ\" alt=\"10 JavaScript Concepts for web analytics\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>This article expands on a conference talk I gave at <a href=\"http:\/\/london.measurecamp.org\/\">MeasureCamp IX, London<\/a> a short while ago. I\u2019ve always been quite single-minded about the importance of JavaScript in web analytics development, and it was a pleasure for me to get some of that off my chest. So I want to go over the ten concepts introduced in my conference talk with a little more detail, especially in the context of <a href=\"https:\/\/tagmanager.google.com\/\">Google Tag Manager<\/a>.<\/p>\n<div style=\"aspect-ratio: 2334 \/ 838;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/title.jpg\" title=\"table of contents\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"838\" width=\"2334\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/title.jpg#ZgotmplZ\" alt=\"table of contents\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>                <span class=\"simmer\"><br \/>\n  <span class=\"close\">X<\/span><\/p>\n<p>\n    <span class=\"fa fa-md fa-bell\"\/><br \/>\n    <strong>The Simmer Newsletter<\/strong>\n  <\/p>\n<p>\n    Subscribe to the <a href=\"https:\/\/www.simoahava.com\/newsletter\/\">Simmer newsletter<\/a> to get the latest news and content from Simo Ahava into your email inbox!\n  <\/p>\n<p>  <\/span><\/p>\n<h2 id=\"get-the-basics-right\">Get the basics right<\/h2>\n<p>JavaScript is not the quirky animation tool from two decades ago anymore &#8211; it\u2019s a programming language if there ever was one. It hides a lot of complexity under its seemingly simple syntax, though in the web browser much of this complexity is either abstracted or removed entirely thanks to how the client-server infrastructure of the web works.<\/p>\n<p>To get up to speed with JavaScript, I typically recommend the following resources. <a href=\"https:\/\/www.codecademy.com\/\">Codecademy<\/a> especially is something you might want to devote time and effort to. It has lots of different tracks, and some that are extremely useful for web (analytics) developers.<\/p>\n<h3 id=\"1-codecademy\">1. Codecademy<\/h3>\n<div style=\"aspect-ratio: 1750 \/ 1454;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/codecademy.jpg\" title=\"codecademy\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"1454\" width=\"1750\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/codecademy.jpg#ZgotmplZ\" alt=\"codecademy\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Codecademy is an <em>amazing<\/em> resource. The courses are free, fully interactive, and the service keeps track of your progress as you learn new skills along the way. Codecademy has lots of tracks for web developers, but I want to highlight the following as the <em>bare minimum<\/em> for web analytics:<\/p>\n<p>I recommend making it habitual to always have a course active in Codecademy. Programming is not a skill you develop in silos &#8211; each new language and discipline you learn helps you become a better developer overall.<\/p>\n<h3 id=\"2-books\">2. Books<\/h3>\n<div style=\"aspect-ratio: 1978 \/ 812;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/books.jpg\" title=\"Great books for learning JavaScript\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"812\" width=\"1978\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/books.jpg#ZgotmplZ\" alt=\"Great books for learning JavaScript\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>You might argue that books are not the best way to keep up-to-date with web technologies, but the following volumes have stood the test of time (with the exception of the last one which is brand new) marvellously, and even if some of the code samples might be outdated, the ideas behind the solutions remain as topical as ever.<\/p>\n<p>Zakas\u2019 volume is a great, if somewhat intimidating, foray into how JavaScript and the web browser interact. Needless to say, it is a goldmine for understanding the technical stack you\u2019re working with when implementing web analytics solution. It\u2019s the book I would most recommend you to read once you have the basics of JavaScript down.<\/p>\n<h3 id=\"3-sandbox\">3. Sandbox<\/h3>\n<p>The only way you can really learn something is by doing it. All creative skills, programming included, need honing. The best way to learn programming is to actively practice it. So in addition to taking courses and learning by reading, remember to also <em>create<\/em> stuff! A great way to do it is to deploy Google Tag Manager on your own website. If you don\u2019t have one, you can now create one with your new-fangled skills!<\/p>\n<p>Play around with the <a href=\"http:\/\/webmasters.stackexchange.com\/a\/77337\/66450\">JavaScript Console<\/a> of your web browser\u2019s developer tools. Implement scripts in Google Tag Manager, and see how they interact with your website. Use tools like <a href=\"http:\/\/www.jslint.com\/\">JS Lint<\/a> to understand what issues your code might have.<\/p>\n<p>Whatever you do, just keep coding.<\/p>\n<div style=\"aspect-ratio: 2038 \/ 212;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/functions-and-methods.jpg\" title=\"1. Functions and Methods\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"212\" width=\"2038\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/functions-and-methods.jpg#ZgotmplZ\" alt=\"1. Functions and Methods\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>In the context of Google Tag Manager, functions are arguably the most useful little things when customizing implementations. That\u2019s because the <a href=\"https:\/\/www.simoahava.com\/analytics\/variable-guide-google-tag-manager\/\">Custom JavaScript Variable<\/a> is basically a function call that you use to resolve a value.<\/p>\n<p>The Custom JavaScript Variable has a very deliberate syntax when using Google Tag Manager, and some of the restrictions might sound odd to you, so I want to go over them with some detail in this chapter.<\/p>\n<h3 id=\"anonymous-function-with-a-return-statement\">Anonymous function with a return statement<\/h3>\n<p>The Custom JavaScript Variable requires an <strong>anonymous function<\/strong> with a <strong><code>return<\/code> statement<\/strong>. An anonymous function is exactly that: it\u2019s a function without a named identifier that you could use to refer to it. Now, you can argue that it does have a name since the Variable itself has a name, but that\u2019s GTM\u2019s proprietary way of resolving the Custom JavaScript Variable and has nothing to do with the underlying JavaScript syntax.<\/p>\n<p>The Custom JavaScript Variable doesn\u2019t take any parameters, either. All values you want to process through it need to come from the internal data model of Google Tag Manager (GTM\u2019s \u201cVariables\u201d), need to be created on the spot (local scope), or need to be available in the global namespace (global scope).<\/p>\n<p>Finally, all Custom JavaScript Variables need a <code>return<\/code> statement. They must always return some value, as they are invoked in situations where a value is required.<\/p>\n<p>So this is the minimum viable Custom JavaScript Variable you could create.<\/p>\n<p>When invoked with the {{Variable}} syntax, this function would return <code>undefined<\/code>.<\/p>\n<h3 id=\"avoid-side-effects\">Avoid side effects<\/h3>\n<p>Since the Custom JavaScript Variable is a value-returning function which does not accept parameters, it should only be used for input\/output operations. Thus, the purpose of the Custom JavaScript Variable is to take some value, modify it, and then return the modified value.<\/p>\n<p>A function has side effects if it does something else except the input\/output operation described in the previous paragraph. Typical side effects occur when a function is used to modify something in the global scope, or it\u2019s used to set some value elsewhere, or, in the context of Google Tag Manager, it\u2019s used to manipulate the Data Layer.<\/p>\n<p>You should avoid side effects because Google Tag Manager can\u2019t guarantee that the Custom JavaScript Variable is only resolved once per activation. In fact, in Preview mode, Custom JavaScript Variables can be resolved dozens of times per <code>dataLayer.push()<\/code>, which can lead to a confusing experience.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">function<\/span>() {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ AVOID THIS:\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#0aa\">window<\/span>.dataLayer.push({<span style=\"color:#a50\">'event'<\/span> : <span style=\"color:#a50\">'JavaScript executed'<\/span>});\n  <span style=\"color:#00a\">return<\/span>;\n}\n<\/code><\/pre>\n<\/div>\n<p>The main problem with side effects is that they\u2019re hard to trace if problems arise. Since the Custom JavaScript Variables are resolved at arbitrary times, having them modify the global scope can be hazardous and can easily lead to unwanted race conditions.<\/p>\n<h3 id=\"understand-scope-utilize-closures\">Understand scope, utilize closures<\/h3>\n<p>JavaScript in the web has two types of scope: local and global.<\/p>\n<p><strong>Local scope<\/strong>, also known as function scope, is what variables are restricted to when declared within a function. When you declare a variable in a function, it will only exist for the duration of the function call (though see the part about closures below), after which the garbage collector comes and whisks it away. Locally scoped variables cannot be referred to or invoked from outside the current function context.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">function<\/span>() {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ These variables all have local scope\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> hello = <span style=\"color:#a50\">\"Hi, \"<\/span>;\n  <span style=\"color:#00a\">var<\/span> myname = <span style=\"color:#a50\">\"Simo!\"<\/span>;\n  <span style=\"color:#00a\">return<\/span> hello + myname;\n}\n<\/code><\/pre>\n<\/div>\n<p><strong>Global scope<\/strong>, on the other hand, comprises variables that are declared as properties of the <code>window<\/code> object. If you don\u2019t use the <code>var<\/code> keyword when declaring a variable in a function, it is automatically elevated into global scope.<\/p>\n<p>When a variable is in global scope, you can refer to it anywhere. For example, the ubiquitous <code>document<\/code> property of the browser\u2019s Document Object Model can be used anywhere since it\u2019s actually a global property of the <code>window<\/code> object:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#0aa\">window<\/span>.<span style=\"color:#0aa\">document<\/span> === <span style=\"color:#0aa\">document<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ true\n<\/span><\/code><\/pre>\n<\/div>\n<p><strong>Closures<\/strong> are an exception to how locally scoped variables are ephemeral and inaccessible from the outside. When you create a closure, you are actually creating a simple <em>interface<\/em> that lets you access the locally scoped variable from outside the function!<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">function<\/span>() {\n  <span style=\"color:#00a\">var<\/span> timeNow = <span style=\"color:#00a\">new<\/span> <span style=\"color:#0aa\">Date<\/span>(); <span style=\"color:#aaa;font-style:italic\">\/\/ Locally scoped\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">function<\/span>() {\n    <span style=\"color:#00a\">return<\/span> <span style=\"color:#a50\">\"Time then was: \"<\/span> + timeNow;\n  };\n}\n<\/code><\/pre>\n<\/div>\n<p>The closure is the <code>return function() {...}<\/code> statement. Because the function is declared within same context, it has access to the locally scoped <code>timeNow<\/code> variable. And because the function is the target of the <code>return<\/code> statement, you can actually call this returned function in code! In the example below, the Custom JavaScript Variable we just created above is named <strong>Time Then<\/strong>.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">var<\/span> timeThen = {{Time Then}}();\nconsole.log(timeThen);\n<\/code><\/pre>\n<\/div>\n<p>The parentheses at the end of the Custom JavaScript Variable are significant. If you simply had <code>{{Time Then}}<\/code>, the variable assignment would store the return value of the Custom JavaScript Variable (the closure) into the <code>timeThen<\/code> variable. The <code>console.log()<\/code> command would simply output the function description itself, and not the result. By adding the parentheses, you\u2019re telling the browser to actually <strong>invoke<\/strong> the function returned by the Custom JavaScript Variable. Since the <code>timeNow<\/code> is only created once (when the Custom JavaScript Variable is first resolved), the closure will always return the same date-time string.<\/p>\n<h3 id=\"modify-state-when-you-are-in-control-of-resolution\">Modify state when you are in control of resolution<\/h3>\n<p>There is one exception to Custom JavaScript Variables having side effects. When you are in full control of when the function is resolved, it\u2019s fine to cause side effects, since you don\u2019t have to worry about the function resolving an unknown number of times or in unknown contexts.<\/p>\n<p>One such example is when using a closure in a <em>callback<\/em>. Callbacks (more on these later) are execution milestones which take place after some other process has completed. So if you indicate the closure of a Custom JavaScript Variable as the value of a callback, you can rest assured that the function is only called once &#8211; when the main process has completed.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">function<\/span>() {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Return a function to be used by hitCallback\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">function<\/span>() {\n    <span style=\"color:#aaa;font-style:italic\">\/\/ It's OK to modify state here!\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#0aa\">window<\/span>.dataLayer.push({<span style=\"color:#a50\">'event'<\/span> : <span style=\"color:#a50\">'tagHasFired'<\/span>});\n  };\n}\n<\/code><\/pre>\n<\/div>\n<p>This process is exemplified in the <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/hitcallback-eventcallback\/\">hitCallback<\/a> feature of the Google Analytics tracker. The hitCallback function is called after the request to Google Analytics has completed. Thus, you can use the closure of a Custom JavaScript Variable to perform some state-altering thing in the hitCallback field itself! This is very useful if you want to chain tags in a sequence, for example.<\/p>\n<h3 id=\"further-reading\">FURTHER READING<\/h3>\n<p>Take a look at the following articles for more information on how functions work:<\/p>\n<div style=\"aspect-ratio: 2030 \/ 228;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/data-types.jpg\" title=\"2. Data Types\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"228\" width=\"2030\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/data-types.jpg#ZgotmplZ\" alt=\"2. Data Types\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>In JavaScript, you have five value-carrying data types:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">var<\/span> something = <span style=\"color:#099\">5<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ number\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> something = <span style=\"color:#a50\">\"five\"<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ string\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> something = <span style=\"color:#00a\">true<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ boolean\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> something = {five: <span style=\"color:#099\">5<\/span>}; <span style=\"color:#aaa;font-style:italic\">\/\/ object\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> something = <span style=\"color:#00a\">function<\/span>() { <span style=\"color:#00a\">return<\/span> <span style=\"color:#099\">5<\/span>; }; <span style=\"color:#aaa;font-style:italic\">\/\/ function\n<\/span><\/code><\/pre>\n<\/div>\n<p>It gets slightly messier than this, since there are actually lots of different types of objects (all JavaScript data types are actually an extension of \u201cobject\u201d in its fundamental sense):<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">var<\/span> something = {five: <span style=\"color:#099\">5<\/span>}; <span style=\"color:#aaa;font-style:italic\">\/\/ Object\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> something = [<span style=\"color:#099\">5<\/span>,<span style=\"color:#099\">5<\/span>,<span style=\"color:#099\">5<\/span>]; <span style=\"color:#aaa;font-style:italic\">\/\/ Array\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> something = <span style=\"color:#00a\">new<\/span> <span style=\"color:#0aa\">Date<\/span>(); <span style=\"color:#aaa;font-style:italic\">\/\/ Date\n<\/span><\/code><\/pre>\n<\/div>\n<p>And finally we have some mystic pseudo-types which don\u2019t carry any value:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">var<\/span> something = <span style=\"color:#00a\">undefined<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ undefined\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> something = <span style=\"color:#00a\">null<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ null\n<\/span><\/code><\/pre>\n<\/div>\n<h3 id=\"dynamic-type\">Dynamic type<\/h3>\n<p>Unlike some other programming languages (e.g. Java), type is <em>dynamic<\/em> in JavaScript. That means that you can reassign a variable with a completely different type without having to worry about type conversion.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">var<\/span> something = <span style=\"color:#099\">5<\/span>;\nsomething = <span style=\"color:#a50\">\"five\"<\/span>;\n<\/code><\/pre>\n<\/div>\n<p>The above is possible in JavaScript, because the variable assignment itself doesn\u2019t coerce the assigned value to any specific type. This can be a weakness in the code, because it requires you to test for type to avoid errors.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#aaa;font-style:italic\">\/\/ Works because something is a number\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> something = <span style=\"color:#099\">5<\/span>;\n<span style=\"color:#00a\">var<\/span> somethingMultiplied = something * <span style=\"color:#099\">2<\/span>;\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ Won't work because something is suddenly a string\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>something = <span style=\"color:#a50\">\"five\"<\/span>;\nsomethingMultiplied = something * <span style=\"color:#099\">2<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ NaN: Not a Number\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\n<span style=\"color:#aaa;font-style:italic\">\/\/ So you need to test\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">if<\/span> (<span style=\"color:#00a\">typeof<\/span> something === <span style=\"color:#a50\">'number'<\/span>) {\n  somethingMultiplied = something * <span style=\"color:#099\">2<\/span>;\n}\n<\/code><\/pre>\n<\/div>\n<p>The further apart your variables are from their execution context, the messier it can get with all the type checks. So try to avoid exploiting dynamic type, and do your best to maintain type when creating and reassigning variables.<\/p>\n<h3 id=\"loose-type\">Loose type<\/h3>\n<p>JavaScript also does type conversion for you when needed. This means that the following is possible:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">var<\/span> something = <span style=\"color:#a50\">\"5\"<\/span>;\n<span style=\"color:#00a\">var<\/span> somethingMultiplied = something * <span style=\"color:#099\">2<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ 10\n<\/span><\/code><\/pre>\n<\/div>\n<p>In the multiplication, JavaScript expects <code>something<\/code> to resolve to the number type. Even though <code>something<\/code> is a string, JavaScript detects the number within and automatically converts the variable to a number for the multiplication statement. The variable <code>something<\/code> itself is not modified, but the value held by it is converted automatically to make resolving <code>somethingMultiplied<\/code> possible.<\/p>\n<p>Note that there are some embarrassing exceptions. The plus operator (+) is not only used for mathematical statements but also for concatenating strings. So if you try to add a number to a string, you\u2019ll end up with a concatenated string rather than a number!<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">var<\/span> a = <span style=\"color:#a50\">\"5\"<\/span>;\n<span style=\"color:#00a\">var<\/span> b = <span style=\"color:#099\">6<\/span>;\n<span style=\"color:#00a\">var<\/span> c = a + b; <span style=\"color:#aaa;font-style:italic\">\/\/ \"56\"!\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\n<span style=\"color:#aaa;font-style:italic\">\/\/ You need to use parseInt() to manually convert to number:\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>c = <span style=\"color:#0aa\">parseInt<\/span>(a) + b; <span style=\"color:#aaa;font-style:italic\">\/\/ 11\n<\/span><\/code><\/pre>\n<\/div>\n<h3 id=\"weird-stuff\">Weird stuff<\/h3>\n<p>I\u2019ll just leave this list here. It\u2019s just a handful off the odd behavior you get when working with loose and dynamic type.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">typeof<\/span> <span style=\"color:#00a\">NaN<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ number\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">NaN<\/span> === <span style=\"color:#00a\">NaN<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ false\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">typeof<\/span> <span style=\"color:#00a\">NaN<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ number\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#0aa\">isNaN<\/span>(<span style=\"color:#00a\">NaN<\/span>); <span style=\"color:#aaa;font-style:italic\">\/\/ true\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#0aa\">isNaN<\/span>(<span style=\"color:#00a\">null<\/span>); <span style=\"color:#aaa;font-style:italic\">\/\/ false\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">typeof<\/span> <span style=\"color:#00a\">null<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ object\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">null<\/span> <span style=\"color:#00a\">instanceof<\/span> <span style=\"color:#0aa\">Object<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ false\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">typeof<\/span> <span style=\"color:#00a\">undefined<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ undefined\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">undefined<\/span> === <span style=\"color:#00a\">null<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ false\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">undefined<\/span> == <span style=\"color:#00a\">null<\/span>; <span style=\"color:#aaa;font-style:italic\">\/\/ true\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>{simo: <span style=\"color:#00a\">true<\/span>} === {simo: <span style=\"color:#00a\">true<\/span>}; <span style=\"color:#aaa;font-style:italic\">\/\/ false\n<\/span><\/code><\/pre>\n<\/div>\n<h3 id=\"undefined-and-google-analytics\">Undefined and Google Analytics<\/h3>\n<p>Remember that the <code>undefined<\/code> type has a <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/undefined-dimensions-wont-get-sent\/\">special function<\/a> in Google Analytics (and Google Tag Manager). If you refer to a variable which returns <code>undefined<\/code>, that particular setting, field, or parameter is automatically dropped from the request to Google Analytics.<\/p>\n<p>In Google Tag Manager, <code>undefined<\/code> can also be used to <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/remember-to-flush-unused-data-layer-variables\/\">purge values from the Data Layer<\/a>. This is extremely useful on single-page apps, where variables persist their values throughout the visit.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#0aa\">window<\/span>.dataLayer.push({\n  event: <span style=\"color:#a50\">'GAEvent'<\/span>,\n  eventData : {\n    cat: <span style=\"color:#a50\">'Category value'<\/span>,\n    act: <span style=\"color:#a50\">'Action value'<\/span>,\n    lab: <span style=\"color:#00a\">undefined<\/span>,\n    val: <span style=\"color:#00a\">undefined<\/span>\n  }\n});\n<\/code><\/pre>\n<\/div>\n<h3 id=\"further-reading-1\">FURTHER READING<\/h3>\n<p>The following articles shed more light on data types in JavaScript:<\/p>\n<div style=\"aspect-ratio: 2024 \/ 200;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/http-requests.jpg\" title=\"3. HTTP Requests\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"200\" width=\"2024\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/http-requests.jpg#ZgotmplZ\" alt=\"3. HTTP Requests\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>When looking for things that can slow down the site, slow or poorly performing HTTP requests are usually the easy culprit to blame.<\/p>\n<p>Thanks to asynchronous loading, most HTTP requests are done in such a way that they don\u2019t block the page from rendering, but async itself doesn\u2019t guarantee a smooth ride.<\/p>\n<p>Let\u2019s take Google Tag Manager as an example. This is a typical container snippet:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\">(<span style=\"color:#00a\">function<\/span>(w,d,s,l,i){w[l]=w[l]||[];w[l].push({<span style=\"color:#a50\">'gtm.start'<\/span>:<span style=\"color:#00a\">new<\/span> <span style=\"color:#0aa\">Date<\/span>().getTime(),event:<span style=\"color:#a50\">'gtm.js'<\/span>});<span style=\"color:#00a\">var<\/span> f=d.getElementsByTagName(s)[<span style=\"color:#099\">0<\/span>],j=d.createElement(s),dl=l!=<span style=\"color:#a50\">'dataLayer'<\/span>?<span style=\"color:#a50\">'&amp;l='<\/span>+l:<span style=\"color:#a50\">''<\/span>;j.async=<span style=\"color:#00a\">true<\/span>;j.src=<span style=\"color:#a50\">'\/\/www.googletagmanager.com\/gtm.js?id='<\/span>+i+dl;f.parentNode.insertBefore(j,f);})(<span style=\"color:#0aa\">window<\/span>,<span style=\"color:#0aa\">document<\/span>,<span style=\"color:#a50\">'script'<\/span>,<span style=\"color:#a50\">'dataLayer'<\/span>,<span style=\"color:#a50\">'GTM-W92WQQ'<\/span>);\n<\/code><\/pre>\n<\/div>\n<p>I\u2019ve gone over this code in an <a href=\"https:\/\/www.simoahava.com\/analytics\/container-snippet-gtm-secrets-revealed\/\">earlier article<\/a>, but suffice to say that the end result of all this code is this:<\/p>\n<div style=\"aspect-ratio: 1430 \/ 258;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/gtm-element.jpg\" title=\"gtm script element\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"258\" width=\"1430\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/gtm-element.jpg#ZgotmplZ\" alt=\"gtm script element\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>In other words, the minified code creates a new <code>script<\/code> HTML element, which instructs the browser to request for a file in Google\u2019s servers, and the request is done asynchronously.<\/p>\n<p>The <code>script<\/code> element, then, turns into an HTTP request, since the <code>src<\/code> attribute in the tag signals the browser to make an HTTP request to the URL value of the attribute.<\/p>\n<div style=\"aspect-ratio: 1096 \/ 274;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/gtm-js-get.jpg\" title=\"gtm.js GET request\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"274\" width=\"1096\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/gtm-js-get.jpg#ZgotmplZ\" alt=\"gtm.js GET request\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>So just by creating the <code>script<\/code> tag, the browser automatically executed an HTTP request to the given endpoint, and the result of this request is the <strong>gtm.js<\/strong> retrieved in the browser for immediate execution.<\/p>\n<p>There are lots of elements that can produce an HTTP request. All scripts, images, and HTML files need to be retrieved from the web server, and the main channel of data transfer is the HTTP request. The following HTML tags (with the given attributes) also invoke HTTP requests:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-html\" data-lang=\"html\">input <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\ninput <span style=\"color:#1e90ff\">usemap<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nins <span style=\"color:#1e90ff\">cite<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nlink <span style=\"color:#1e90ff\">href<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nobject <span style=\"color:#1e90ff\">classid<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nobject <span style=\"color:#1e90ff\">codebase<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nobject <span style=\"color:#1e90ff\">data<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nobject <span style=\"color:#1e90ff\">usemap<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nq <span style=\"color:#1e90ff\">cite<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nscript <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;\naudio <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nbutton <span style=\"color:#1e90ff\">formaction<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\ncommand <span style=\"color:#1e90ff\">icon<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nembed <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nhtml <span style=\"color:#1e90ff\">manifest<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\ninput <span style=\"color:#1e90ff\">formaction<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nsource <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nvideo <span style=\"color:#1e90ff\">poster<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nvideo <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\na <span style=\"color:#1e90ff\">href<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\napplet <span style=\"color:#1e90ff\">codebase<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\narea <span style=\"color:#1e90ff\">href<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nbase <span style=\"color:#1e90ff\">href<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nblockquote <span style=\"color:#1e90ff\">cite<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nbody <span style=\"color:#1e90ff\">background<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\ndel <span style=\"color:#1e90ff\">cite<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nform <span style=\"color:#1e90ff\">action<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nframe <span style=\"color:#1e90ff\">longdesc<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nframe <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nhead <span style=\"color:#1e90ff\">profile<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\niframe <span style=\"color:#1e90ff\">longdesc<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\niframe <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nimg <span style=\"color:#1e90ff\">longdesc<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nimg <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;\nimg <span style=\"color:#1e90ff\">usemap<\/span>=<span style=\"color:#a50\">\"url\"<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>Yeah. That\u2019s quite a bunch.<\/p>\n<p>Note that HTTP requests can be created manually using e.g. <code>XMLHttpRequest<\/code> or <code>jQuery.ajax()<\/code>. In fact, when you send hits to Google Analytics, you\u2019re actually using HTTP requests created by the <strong>analytics.js<\/strong> library.<\/p>\n<div style=\"aspect-ratio: 752 \/ 534;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/collect-get-post.jpg\" title=\"GET and POST in google analytics requests\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"534\" width=\"752\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/collect-get-post.jpg#ZgotmplZ\" alt=\"GET and POST in google analytics requests\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<h3 id=\"further-reading-2\">FURTHER READING<\/h3>\n<p>Here\u2019s more information on HTTP requests:<\/p>\n<div style=\"aspect-ratio: 2018 \/ 218;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/race-conditions.jpg\" title=\"4. Race Conditions\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"218\" width=\"2018\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/race-conditions.jpg#ZgotmplZ\" alt=\"4. Race Conditions\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>The difference between <strong>asynchronous<\/strong> and <strong>synchronous<\/strong> loading is subtle but significant.<\/p>\n<p>JavaScript in the web browser is <strong>single-threaded<\/strong>. That means that only one process can ever be running at a time, and thus every single line of JavaScript must be executed completely before the browser can proceed to the next line. If you make a <strong>synchronous<\/strong> HTTP request, it means that the browser will wait until the entire request (download, execution, render) is taken to completion before the browser proceeds to the next line of code in the page. It\u2019s said that synchronous operations are thus <strong>blocking<\/strong>.<\/p>\n<p>To counter this potentially devastating blow to page render and user experience, asynchronous loading was introduced to make the \u201cexpensive\u201d part of the process, the download, happen so that it doesn\u2019t block the browser.<\/p>\n<p>So, when a request is made asynchronously, the browser initiates the download but then proceeds to the next line of code <em>while the download goes on in the background<\/em>. Only after the file is completely downloaded, does the browser return execution to this initial process, rendering the downloaded asset in the browser.<\/p>\n<p>The problem with asynchronous execution is that even though you can pinpoint the exact moment when the request is initiated, as it\u2019s governed by the order of the lines of code in the page template, you\u2019ll never know the exact moment when it completes. And this can lead to something called a <strong>race condition<\/strong>.<\/p>\n<p>So let\u2019s say I have the following two lines of code in the page template:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-html\" data-lang=\"html\">script <span style=\"color:#1e90ff\">async<\/span> <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/3.1.0\/jquery.min.js\"<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;\nscript <span style=\"color:#1e90ff\">async<\/span>=<span style=\"color:#a50\">\"\"<\/span> <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"https\/\/www.googletagmanager.com\/gtm.js?id=GTM-XXXXX\"<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>The browser starts loading the jQuery library before GTM, so I might expect jQuery to available to GTM as soon as the latter has finished downloading. But that\u2019s not necessarily the case! The actual download of jQuery can end long <em>after<\/em> GTM has completed, because the jQuery library is more often than not quite a bulky thing. Also, if the CDN providing the jQuery library has latency, it might affect when jQuery becomes available.<\/p>\n<p>So, if in Google Tag Manager I try to use jQuery, there can be a <strong>race condition<\/strong> where GTM expects jQuery to be available but it isn\u2019t.<\/p>\n<p>To combat the race condition, we can use tools like <strong>callbacks<\/strong>, <strong>promises<\/strong> or, in GTM, <a href=\"https:\/\/www.simoahava.com\/analytics\/understanding-tag-sequencing-in-google-tag-manager\/\">Tag Sequencing<\/a>. You can always resort to synchronous downloading if you\u2019re really concerned about race conditions, but remember that this can have a detrimental impact on user experience.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-html\" data-lang=\"html\"><span style=\"color:#aaa;font-style:italic\"><!-- Synchronous request --><\/span>\nscript <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/3.1.0\/jquery.min.js\"<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;\nscript <span style=\"color:#1e90ff\">async<\/span>=<span style=\"color:#a50\">\"\"<\/span> <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"https\/\/www.googletagmanager.com\/gtm.js?id=GTM-XXXXX\"<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;\n\n<span style=\"color:#aaa;font-style:italic\"><!-- Callback --><\/span>\nscript&gt;\n  (<span style=\"color:#00a\">function<\/span>() {\n    <span style=\"color:#00a\">var<\/span> el = <span style=\"color:#0aa\">document<\/span>.createElement(<span style=\"color:#a50\">'script'<\/span>);\n    el.src = <span style=\"color:#a50\">'https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/3.1.0\/jquery.min.js'<\/span>;\n    el.async = <span style=\"color:#00a\">true<\/span>;\n    el.addEventListener(<span style=\"color:#a50\">'load'<\/span>, <span style=\"color:#00a\">function<\/span>() {\n      <span style=\"color:#0aa\">window<\/span>.dataLayer.push({event: <span style=\"color:#a50\">'jQueryLoaded'<\/span>});\n    });\n    <span style=\"color:#0aa\">document<\/span>.head.appendChild(el);\n  })();\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;\n\n<span style=\"color:#aaa;font-style:italic\"><!-- Tag Sequencing --><\/span>\nscript&gt;\n  (<span style=\"color:#00a\">function<\/span>() {\n    <span style=\"color:#00a\">var<\/span> el = <span style=\"color:#0aa\">document<\/span>.createElement(<span style=\"color:#a50\">'script'<\/span>);\n    el.src = <span style=\"color:#a50\">'https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/3.1.0\/jquery.min.js'<\/span>;\n    el.async = <span style=\"color:#00a\">true<\/span>;\n    el.addEventListener(<span style=\"color:#a50\">'load'<\/span>, <span style=\"color:#00a\">function<\/span>() {\n      <span style=\"color:#0aa\">window<\/span>[<span style=\"color:#a50\">'google_tag_maanger'<\/span>][{{Container ID}}].onHtmlSuccess({{HTML ID}});\n    });\n    <span style=\"color:#0aa\">document<\/span>.head.appendChild(el);\n  })();\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>It\u2019s better to be safe than sorry, so when working with potential race conditions, make sure to always check if the resources you are trying to use actually exist.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">if<\/span> (<span style=\"color:#00a\">typeof<\/span> jQuery !== <span style=\"color:#a50\">'undefined'<\/span>) {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Use jQuery\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>} <span style=\"color:#00a\">else<\/span> {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Use something else\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>}\n<\/code><\/pre>\n<\/div>\n<h3 id=\"further-reading-3\">FURTHER READING<\/h3>\n<p>Here are some useful links on race conditions, callbacks, and such.<\/p>\n<div style=\"aspect-ratio: 1984 \/ 206;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/history-manipulation.jpg\" title=\"5. History Manipulation\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"206\" width=\"1984\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/history-manipulation.jpg#ZgotmplZ\" alt=\"5. History Manipulation\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Single-page_application\">Single-page web applications<\/a> (SPA) utilize something called the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/History_API\">History API<\/a> to provide a multi-page experience with only one initial page load in the web server. Subsequent transitions from page-to-page are commonly done using the History API, by withdrawing content from the server without initiating a page refresh, and manually creating history entries in the web browser. Common frameworks for SPAs are e.g. <a href=\"https:\/\/facebook.github.io\/react\/\">React<\/a>, <a href=\"https:\/\/angularjs.org\/\">AngularJS<\/a>, and <a href=\"http:\/\/backbonejs.org\/\">Backbone.js<\/a>.<\/p>\n<p>SPAs have significant implications for web analytics. For example, an SPA can suffer from the <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/be-careful-with-the-tracker-name-setting\/\">rogue referrer<\/a> problem, where URL query parameters that are used for campaign settings are overwritten by a subsequent page view hit. For Google Tag Manager, the problem of persistence rears its ugly head, where variables maintain the values you set earlier, leading to these values bleeding into subsequent tags.<\/p>\n<p>Browser history is manipulated because when content is dynamically loaded, the site needs to tell the web browser that the user has entered a new page without the benefit of the page reload doing this automatically. Otherwise you wouldn\u2019t be able to link to dynamic content, nor would the Back and Forward buttons of the browser find your dynamic content.<\/p>\n<p>The two interfaces you\u2019ll run into most often are <code>pushState<\/code> and <code>replaceState<\/code>. The former creates a new history entry in the web browser, and the latter replaces the current entry entirely. Here are examples of how to use them:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#0aa\">window<\/span>.history.pushState(\n  {pageType: <span style=\"color:#a50\">'formThankYou'<\/span>},\n  <span style=\"color:#a50\">'Form Success'<\/span>,\n  <span style=\"color:#a50\">'\/thank-you\/'<\/span>\n);\n<\/code><\/pre>\n<\/div>\n<p>When you run this command, the URL changes to \/thank-you\/ without a page reload. The first two parameters add additional information about the state. If you now click the Back button of the browser, you are taken to the URL where you called <code>pushState<\/code>.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#0aa\">window<\/span>.history.replaceState(\n  {pageType: <span style=\"color:#a50\">'formThankyou'<\/span>},\n  <span style=\"color:#a50\">'Form Success'<\/span>,\n  <span style=\"color:#a50\">'\/thank-you\/'<\/span>\n);\n<\/code><\/pre>\n<\/div>\n<p>When you execute this command, it actually <em>replaces<\/em> the current page in the browser history. In other words, when you click the browser\u2019s Back button, you are taken to the page you were on <em>before<\/em> you entered the page from where you called <code>replaceState<\/code>.<\/p>\n<p>Note that if you simply add <strong>#someHash<\/strong> in the URL, it\u2019s the equivalent of calling <code>pushState<\/code> without the benefit of the other parameters in the interface (e.g. the state object).<\/p>\n<p>In Google Tag Manager, you have a <strong>really<\/strong> useful Trigger type called the <a href=\"https:\/\/www.simoahava.com\/analytics\/google-tag-manager-history-listener\/\">History Change<\/a> Trigger. It goes off whenever one of the following History events occur:<\/p>\n<ul>\n<li><strong>pushState<\/strong><\/li>\n<li><strong>replaceState<\/strong><\/li>\n<li><strong>hashchange<\/strong> (when the #someHash in the URL appears\/changes)<\/li>\n<li><strong>popstate<\/strong> (when the active history entry changes)<\/li>\n<\/ul>\n<p>For example, if you want to build pageviews around these history events, it\u2019s quite <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/track-url-fragments-as-pageviews\/\">simple to do<\/a> with the History Change Trigger!<\/p>\n<h3 id=\"further-reading-4\">FURTHER READING<\/h3>\n<p>For more information on the Window History API, look no further than these articles:<\/p>\n<div style=\"aspect-ratio: 2016 \/ 212;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/browser-storage.jpg\" title=\"6. Browser Storage\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"212\" width=\"2016\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/browser-storage.jpg#ZgotmplZ\" alt=\"6. Browser Storage\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>The web page is stateless. With every page load, the <em>entire<\/em> page is built from scratch. All the variables, JavaScript libraries, HTML templates, CSS files and other resources are loaded again.<\/p>\n<p>In other words, if the web browser needs to know something, <em>anything<\/em>, about what happened at any time in the past, you need to manually persist this information.<\/p>\n<p>You can persist the information in the web server, and this is often quite a robust way to do it. However, because of how the web is built, you still need a way of aligning any given web browser (and thus, user) with the requests that are sent to the web server.<\/p>\n<p>The web browser provides a number of ways to persist this information. The most common methods are browser cookies, Web Storage, and <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/IndexedDB_API\">IndexedDB<\/a>.<\/p>\n<div style=\"aspect-ratio: 392 \/ 450;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/webstorage.jpg\" title=\"Browser storage\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"450\" width=\"392\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/webstorage.jpg#ZgotmplZ\" alt=\"Browser storage\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<h3 id=\"browser-cookies\">Browser cookies<\/h3>\n<p>Browser cookies are useful for simple storage. The browser cookie is essentially a string stored by the web browser, and its accessible only by pages that share the same parent domain to which the cookie was written. So a cookie written on <strong><a href=\"https:\/\/www.simoahava.com\">www.simoahava.com<\/a><\/strong> would, by default, only be available to pages on <strong><a href=\"https:\/\/www.simoahava.com\">www.simoahava.com<\/a><\/strong>, but you could also write the cookie on <strong>simoahava.com<\/strong>, where it would be available to all subdomains.<\/p>\n<p>A cookie written on <strong>simoahava.com<\/strong> would <em>not<\/em> be available for pages on <strong>derekahava.com<\/strong>, because they do not share the same domain.<\/p>\n<p>Cookies also survive transitions from the http:\/\/ protocol to https:\/\/.<\/p>\n<h3 id=\"web-storage\">Web Storage<\/h3>\n<p>Web Storage (or DOM Storage) encompasses both <code>localStorage<\/code> (no expiration) and <code>sessionStorage<\/code> (expires when the web browser is closed). Web Storage is much more flexible than using cookies, because the entries are stored as a hash table, and lookups can be done on a key-by-key basis. With cookies, you need to unravel the entire cookie string just to find the value want.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#aaa;font-style:italic\">\/\/ TO SET\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">if<\/span> (<span style=\"color:#0aa\">window<\/span>[<span style=\"color:#a50\">'Storage'<\/span>]) {\n  localStorage.setItem(<span style=\"color:#a50\">'subscribe'<\/span>, <span style=\"color:#a50\">'true'<\/span>); \n  sessionStorage.setItem(<span style=\"color:#a50\">'subscribe'<\/span>, <span style=\"color:#a50\">'true'<\/span>);\n} <span style=\"color:#00a\">else<\/span> {\n  setCookie(<span style=\"color:#a50\">'subscribe'<\/span>, <span style=\"color:#a50\">'true'<\/span>);\n}\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ TO FETCH\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>localStorage.getItem(<span style=\"color:#a50\">'subscribe'<\/span>);\nsessionStorage.getItem(<span style=\"color:#a50\">'subscribe'<\/span>);\n<\/code><\/pre>\n<\/div>\n<p>Note that Web Storage does <em>not<\/em> survive the transition from http:\/\/ to https:\/\/. Both protocols have their own storage.<\/p>\n<h3 id=\"indexeddb\">IndexedDB<\/h3>\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/IndexedDB_API\">IndexedDB<\/a> is much more complex than the aforementioned methods, and is thus more suited for application logic on a much larger scale. For example, if you\u2019re using <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Service_Worker_API\">Service Workers<\/a> to maintain offline browsing capabilities, IndexedDB is an excellent utility to maintain state while waiting for the internet connection to come back up.<\/p>\n<p>Checkout the link to my article on persisting data in Google Tag Manager for more information (and some tips) on how to setup cookie and Web Storage persistence in GTM!<\/p>\n<h3 id=\"further-reading-5\">FURTHER READING<\/h3>\n<p>Check out the following links for more information:<\/p>\n<div style=\"aspect-ratio: 2022 \/ 252;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/dom-traversal-1.jpg\" title=\"7. DOM traversal\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"252\" width=\"2022\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/dom-traversal-1.jpg#ZgotmplZ\" alt=\"7. DOM traversal\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Locating elements on the page is one of the more obvious use cases for web analytics. Most commonly we want to know if some specific element was the target of a user action such as a click or form submission.<\/p>\n<p>In Google Tag Manager, identifying an element is easy enough with CSS selectors, but what if we actually want to <em>retrieve<\/em> some element other than what GTM initially gave us?<\/p>\n<div style=\"aspect-ratio: 1914 \/ 638;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/dom-traversal.jpg\" title=\"DOM traversal example\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"638\" width=\"1914\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/dom-traversal.jpg#ZgotmplZ\" alt=\"DOM traversal example\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>There are many ways to retrieve an element relative to some other with JavaScript. A very clumsy way to do it would be to build a complete element chain all between the two elements. So if you wanted to retrieve the element at the top of the DOM in the image above, you could do something like this in a Custom JavaScript Variable:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">function<\/span>() {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Please don't do this:\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">return<\/span> {{Click Element}}\n    .parentElement\n    .parentElement\n    .parentElement\n    .parentElement\n    .parentElement;\n}\n<\/code><\/pre>\n<\/div>\n<p>But please don\u2019t do this. It\u2019s clumsy and it has multiple points of failure. You\u2019re basically expecting the DOM to have a certain structure without providing any redundancies or fallbacks. The longer the chain, the more sensitive it is to even minor changes to the page markup.A better way is to disregard the actual number of elements, and just climb up the DOM until you reach the very top.<\/p>\n<p>So a more robust way of retrieving the element would be something like this:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">function<\/span>() {\n  <span style=\"color:#00a\">var<\/span> el = {{Click Element}};\n  \n  <span style=\"color:#00a\">while<\/span> (el.className !== <span style=\"color:#a50\">'content-sidebar-wrap'<\/span> &amp;&amp; el.tagName !== <span style=\"color:#a50\">'BODY'<\/span>) {\n    el = el.parentElement;\n  }\n\n  <span style=\"color:#00a\">return<\/span> el.tagName !== <span style=\"color:#a50\">'BODY'<\/span> ? el : <span style=\"color:#00a\">undefined<\/span>;\n}\n<\/code><\/pre>\n<\/div>\n<p>This little script simply climbs up the DOM until it either reaches the element you wanted (<code>.content-sidebar-wrap<\/code>) or the <code\/> tag. If it reaches <code\/>, the assumption is that the element you were looking for was not found, and <code>undefined<\/code> is returned instead.<\/p>\n<p>Note that this script only works for direct ancestry. If you want to find sibling elements or elements which branch from the direct path between the original element and the root of the document, you might want to leverage frameworks like jQuery to make DOM traversal code more economic.<\/p>\n<h3 id=\"further-reading-6\">FURTHER READING<\/h3>\n<p>Follow these links to find more information on DOM traversal:<\/p>\n<div style=\"aspect-ratio: 2014 \/ 220;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/css-selectors.jpg\" title=\"8. CSS Selectors\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"220\" width=\"2014\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/css-selectors.jpg#ZgotmplZ\" alt=\"8. CSS Selectors\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>When Google Tag Manager introduced the <a href=\"https:\/\/www.simoahava.com\/analytics\/matches-css-selector-operator-in-gtm-triggers\/\">matches CSS selector<\/a> Trigger operator a while ago, it eliminated a lot of complexity from validating Triggers to only fire for certain HTML element interactions. In a similar manner, the <code>querySelector<\/code> and <code>querySelectorAll<\/code> JavaScript DOM methods were just as impactful when they were introduced some years ago into the web browser API.<\/p>\n<p>If you\u2019ve built websites or worked with CSS (Cascading Style Sheets) styles before, you\u2019ll know what selectors do. They let you select any element or group of elements on the page, and then apply a style to them. For example, the following style declaration would remove the default <em>underline<\/em> from all links (<code><a\/><\/code>) with class <code>internal<\/code>:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-css\" data-lang=\"css\"><span style=\"color:#1e90ff;font-weight:bold\">a<\/span>.<span style=\"color:#0a0;text-decoration:underline\">internal<\/span> {\n    <span style=\"color:#00a\">text-decoration<\/span>: <span style=\"color:#00a\">none<\/span>;\n}<\/code><\/pre>\n<\/div>\n<p>Because it\u2019s such an effective way of selecting HTML elements, it\u2019s not a big surprise that JavaScript introduced methods for using CSS selectors to find and retrieve HTML elements on the page:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#aaa;font-style:italic\">\/\/ Select every link with attribute data-gtm on the page:\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> gtmLinks = <span style=\"color:#0aa\">document<\/span>.querySelectorAll(<span style=\"color:#a50\">'a[data-gtm]'<\/span>);\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ Select the first 'h2' element on the page, which is the direct child of 'section'\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> firstH2 = <span style=\"color:#0aa\">document<\/span>.querySelector(<span style=\"color:#a50\">'section &gt; h2'<\/span>);\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ Select the 'span' with class 'title' that is a descendant of the aforementioned 'h2'\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> spanTitle = firstH2.querySelector(<span style=\"color:#a50\">'span.title'<\/span>);\n<\/code><\/pre>\n<\/div>\n<p>Similarly, if you already <em>have<\/em> an HTML element, you can use the <code>matches<\/code> API to check if it matches a specific CSS selector:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">var<\/span> isElementLink = <span style=\"color:#00a\">function<\/span>(el) {\n  <span style=\"color:#00a\">return<\/span> el.matches(<span style=\"color:#a50\">'a'<\/span>);\n}\n<\/code><\/pre>\n<\/div>\n<p>The function above would return <code>true<\/code> or <code>false<\/code>, depending on whether the element passed as a parameter is a link or not. Note that <code>matches<\/code> isn\u2019t widely supported yet, but there\u2019s a <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Element\/matches#Polyfill\">polyfill you can use<\/a> to make it work across all browsers.<\/p>\n<p>In Google Tag Manager, the <a href=\"https:\/\/www.simoahava.com\/analytics\/matches-css-selector-operator-in-gtm-triggers\/\">matches CSS selector<\/a> is ridiculously useful. You can use it to fire your Triggers only when a specific element is the target of the interaction. For example, I could configure a Click \/ All Elements Trigger like the following to make it only fire when the clicked element is a specific <code><span\/><\/code> (or any of its nested descendants) on the page!<\/p>\n<div style=\"aspect-ratio: 1748 \/ 446;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/gtm-css.jpg\" title=\"matches CSS selector in GTM\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"446\" width=\"1748\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/gtm-css.jpg#ZgotmplZ\" alt=\"matches CSS selector in GTM\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>CSS selectors shave a crazy amount of time off your JavaScript, as you don\u2019t have to write clumsy comparison queries using DOM traversal when trying to identify a specific element. Take a look at the further reading links below to learn more about CSS selectors!<\/p>\n<h3 id=\"further-reading-7\">FURTHER READING<\/h3>\n<p>More stuff about CSS selectors:<\/p>\n<div style=\"aspect-ratio: 2016 \/ 216;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/jquery.jpg\" title=\"9. jQuery\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"216\" width=\"2016\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/jquery.jpg#ZgotmplZ\" alt=\"9. jQuery\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p><a href=\"http:\/\/jquery.com\/\">jQuery<\/a> is undoubtedly the most used JavaScript library in the world, and its contributions to standardizing the web experience across browsers and devices should not and do not go unnoticed. The framework provides such a wealth of utilities that trivialize and abstract many of the woes a web developer might have when developing their site to be as accessible across the splintered browser landscape as possible.<\/p>\n<p>In short, jQuery is a library which provides a bunch of simple APIs to perform otherwise complex tasks. For example, let\u2019s take the DOM traversal example from chapter 7 and rewrite it with jQuery:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#aaa;font-style:italic\">\/\/ Vanilla JS\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">function<\/span>() {\n  <span style=\"color:#00a\">var<\/span> el = {{Click Element}};\n  \n  <span style=\"color:#00a\">while<\/span> (el.className !== <span style=\"color:#a50\">'content-sidebar-wrap'<\/span> &amp;&amp; el.tagName !== <span style=\"color:#a50\">'BODY'<\/span>) {\n    el = el.parentElement;\n  }\n\n  <span style=\"color:#00a\">return<\/span> el.tagName !== <span style=\"color:#a50\">'BODY'<\/span> ? el : <span style=\"color:#00a\">undefined<\/span>;\n}\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ jQuery\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">function<\/span>() {\n  <span style=\"color:#00a\">return<\/span> jQuery({{Click Element}}).closest(<span style=\"color:#a50\">'.content-sidebar-wrap'<\/span>)[<span style=\"color:#099\">0<\/span>];\n}\n<\/code><\/pre>\n<\/div>\n<p>So a single line of jQuery abstracted the previous implementation.<\/p>\n<p>Similarly, here\u2019s the difference between building a custom HTTP POST request using regular JavaScript versus using jQuery:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#aaa;font-style:italic\">\/\/ Vanilla JS\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> xhr = <span style=\"color:#00a\">new<\/span> XMLHttpRequest();\n<span style=\"color:#00a\">var<\/span> payload = <span style=\"color:#a50\">'v=1&amp;tid=UA-12345-1&amp;t=pageview&amp;dl=https:\/\/www.simoahava.com\/&amp;cid=12345.12345'<\/span>;\n\nxhr.open(<span style=\"color:#a50\">'POST'<\/span>, <span style=\"color:#a50\">'https:\/\/www.google-analytics.com\/collect'<\/span>);\nxhr.setRequestHeader(<span style=\"color:#a50\">'Content-Type'<\/span>, <span style=\"color:#a50\">'application\/x-www-form-urlencoded'<\/span>);\nxhr.onload = <span style=\"color:#00a\">function<\/span>() {\n  <span style=\"color:#00a\">if<\/span> (xhr.status === <span style=\"color:#099\">200<\/span>) {\n    alert(<span style=\"color:#a50\">'Yay!'<\/span>);\n  }\n  <span style=\"color:#00a\">else<\/span> <span style=\"color:#00a\">if<\/span> (xhr.status !== <span style=\"color:#099\">200<\/span>) {\n    alert(<span style=\"color:#a50\">'Aww :('<\/span>);\n  }\n};\nxhr.send(<span style=\"color:#0aa\">encodeURI<\/span>(payload));\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ jQuery\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>jQuery.post(\n  <span style=\"color:#a50\">'https:\/\/www.google-analytics.com\/collect'<\/span>,\n  <span style=\"color:#a50\">'v=1&amp;tid=UA-12345-1&amp;t=pageview&amp;dl=https:\/\/www.simoahava.com\/&amp;cid=12345.12345'<\/span>\n)\n  .done(<span style=\"color:#00a\">function<\/span>() {\n    alert(<span style=\"color:#a50\">'Yay!'<\/span>);\n  })\n  .fail(<span style=\"color:#00a\">function<\/span>() {\n    alert(<span style=\"color:#a50\">'Aww :('<\/span>);\n  });\n<\/code><\/pre>\n<\/div>\n<p>I hope you see the trend here. jQuery really makes things more elegant for both the developer as well as for anyone who wants to look at the code and quickly understand what it tries to do.<\/p>\n<p>jQuery isn\u2019t all-powerful, though, and relying too much on a framework can make your code weak. My suggestion is to always understand what a given jQuery method does before using it. That way you\u2019ll know what the background process is, and you\u2019ll learn to avoid nasty surprises such as how <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/fix-problems-with-gtm-listeners\/\">jQuery\u2019s <code>return false;<\/code> in event handlers can break GTM\u2019s listeners<\/a>!<\/p>\n<p>Remember also to be wary of race conditions when loading jQuery.<\/p>\n<div style=\"aspect-ratio: 1876 \/ 764;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/jquery-load.jpg\" title=\"jQuery race conditions\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"764\" width=\"1876\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/jquery-load.jpg#ZgotmplZ\" alt=\"jQuery race conditions\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>If you load the library asynchronously, it might not be ready by the time you refer to it in your GTM Tags.<\/p>\n<h3 id=\"further-reading-8\">FURTHER READING<\/h3>\n<p>And here\u2019s the scoop on jQuery:<\/p>\n<div style=\"aspect-ratio: 2014 \/ 210;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/09\/data-layer.jpg\" title=\"10. Data Layer\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"210\" width=\"2014\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/09\/data-layer.jpg#ZgotmplZ\" alt=\"10. Data Layer\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Finally, the Data Layer. If you\u2019ve used GTM or any tag management solution, it\u2019s probably you\u2019ve had to really put some thought into understanding how tag management solutions leverage the Data Layer to communicate with the website or other digital property.<\/p>\n<p>It\u2019s not purely a JavaScript concept, so it\u2019s kind of a black sheep in this mix. Nevertheless, the most typical implementation of a Data Layer, when it comes to tag management solutions, is an Array-type data structure in the global namespace.<\/p>\n<p>I\u2019ve written about Data Layer quite a lot on this blog, so instead of repeating what I\u2019ve already written far more extensively, I want to direct you to the links below and I strongly suggest you read through them to get a better idea of how the Data Layer works.<\/p>\n<h3 id=\"further-reading-9\">FURTHER READING<\/h3>\n<p>Be sure to check these links out for more information on the Data Layer:<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>The ten JavaScript concepts introduced in this article are, what I consider, the most useful tools that any web analyst would need to know about. Heck, I consider these vital to anyone working with the web, not just analysts!<\/p>\n<p>The thing is, we\u2019re working in an extremely technical medium. The web browser is tantalizingly complex in all its machinations, and it doesn\u2019t really help that all web browsers act slightly differently when it comes to producing the web document into our screens.<\/p>\n<p>When working with web analytics, we are trying to decipher the abstract signals sent by users, web servers, the browser itself, and background processes, as we do our best to align these signals with their real-world counterparts.<\/p>\n<p>It\u2019s not easy!<\/p>\n<p>Trying to deconstruct the enormously difficult concepts of \u201cintent\u201d, \u201cengagement\u201d, and \u201cinteraction\u201d using a handful of JavaScript handlers seems like a fool\u2019s errand, but it\u2019s the only thing we can do when creating an implementation framework for any given web application.<\/p>\n<p>But the more we know about JavaScript and the numerous APIs that the web browser lets us tap into, the more we can uncover about our visitors and their actions on the site.<\/p>\n<p>I hope you found these tips useful. Do you have other JavaScript concepts that you consider are absolutely essential for anyone working with the web to acquaint themselves with?<\/p>\n<\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>I\u2019ve already written extensively about JavaScript in web analytics implementation. Suffice to say, understanding at least the basics is absolutely necessary to survive in the technical medium of the web browser. This article expands on a conference talk I gave at MeasureCamp IX, London a short while ago. I\u2019ve always been quite single-minded about the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":126867,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[12765,11387,17296,29091,5393],"dealstore":[],"offerexpiration":[],"class_list":["post-126866","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-analytics","tag-concepts","tag-implementation","tag-javascript","tag-web"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>10 JavaScript Concepts For Web Analytics Implementation - Som2ny Network<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fivemor.com\/?p=126866\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"10 JavaScript Concepts For Web Analytics Implementation - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"I\u2019ve already written extensively about JavaScript in web analytics implementation. Suffice to say, understanding at least the basics is absolutely necessary to survive in the technical medium of the web browser. This article expands on a conference talk I gave at MeasureCamp IX, London a short while ago. I\u2019ve always been quite single-minded about the [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=126866\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-03-11T18:46:25+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/10-javascript-concepts.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2048\" \/>\n\t<meta property=\"og:image:height\" content=\"1142\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"29 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=126866#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=126866\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"10 JavaScript Concepts For Web Analytics Implementation\",\"datePublished\":\"2025-03-11T18:46:25+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=126866\"},\"wordCount\":4823,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=126866#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/10-javascript-concepts.jpg\",\"keywords\":[\"Analytics\",\"Concepts\",\"Implementation\",\"JavaScript\",\"Web\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=126866#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=126866\",\"url\":\"https:\/\/fivemor.com\/?p=126866\",\"name\":\"10 JavaScript Concepts For Web Analytics Implementation - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=126866#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=126866#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/10-javascript-concepts.jpg\",\"datePublished\":\"2025-03-11T18:46:25+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=126866#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=126866\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=126866#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/10-javascript-concepts.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/10-javascript-concepts.jpg\",\"width\":2048,\"height\":1142},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=126866#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"10 JavaScript Concepts For Web Analytics Implementation\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fivemor.com\/#website\",\"url\":\"https:\/\/fivemor.com\/\",\"name\":\"Som2ny Network\",\"description\":\"Daily Deals\",\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fivemor.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/fivemor.com\/#organization\",\"name\":\"Som2ny Network\",\"url\":\"https:\/\/fivemor.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png\",\"width\":300,\"height\":86,\"caption\":\"Som2ny Network\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png\",\"caption\":\"admin\"},\"sameAs\":[\"https:\/\/fivemor.com\"],\"url\":\"https:\/\/fivemor.com\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"10 JavaScript Concepts For Web Analytics Implementation - Som2ny Network","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fivemor.com\/?p=126866","og_locale":"en_US","og_type":"article","og_title":"10 JavaScript Concepts For Web Analytics Implementation - Som2ny Network","og_description":"I\u2019ve already written extensively about JavaScript in web analytics implementation. Suffice to say, understanding at least the basics is absolutely necessary to survive in the technical medium of the web browser. This article expands on a conference talk I gave at MeasureCamp IX, London a short while ago. I\u2019ve always been quite single-minded about the [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=126866","og_site_name":"Som2ny Network","article_published_time":"2025-03-11T18:46:25+00:00","og_image":[{"width":2048,"height":1142,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/10-javascript-concepts.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"29 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=126866#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=126866"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"10 JavaScript Concepts For Web Analytics Implementation","datePublished":"2025-03-11T18:46:25+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=126866"},"wordCount":4823,"commentCount":0,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=126866#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/10-javascript-concepts.jpg","keywords":["Analytics","Concepts","Implementation","JavaScript","Web"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=126866#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=126866","url":"https:\/\/fivemor.com\/?p=126866","name":"10 JavaScript Concepts For Web Analytics Implementation - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=126866#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=126866#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/10-javascript-concepts.jpg","datePublished":"2025-03-11T18:46:25+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=126866#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=126866"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=126866#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/10-javascript-concepts.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/10-javascript-concepts.jpg","width":2048,"height":1142},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=126866#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"10 JavaScript Concepts For Web Analytics Implementation"}]},{"@type":"WebSite","@id":"https:\/\/fivemor.com\/#website","url":"https:\/\/fivemor.com\/","name":"Som2ny Network","description":"Daily Deals","publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fivemor.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/fivemor.com\/#organization","name":"Som2ny Network","url":"https:\/\/fivemor.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/#\/schema\/logo\/image\/","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png","width":300,"height":86,"caption":"Som2ny Network"},"image":{"@id":"https:\/\/fivemor.com\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371","name":"admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png","caption":"admin"},"sameAs":["https:\/\/fivemor.com"],"url":"https:\/\/fivemor.com\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/126866","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=126866"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/126866\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/126867"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=126866"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=126866"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=126866"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=126866"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=126866"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}