{"id":147673,"date":"2025-03-21T12:30:12","date_gmt":"2025-03-21T12:30:12","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/universal-analytics-plugins-explained-simo-ahavas-blog\/"},"modified":"2025-03-21T12:30:12","modified_gmt":"2025-03-21T12:30:12","slug":"universal-analytics-plugins-explained-simo-ahavas-blog","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=147673","title":{"rendered":"Universal Analytics Plugins Explained | Simo Ahava&#8217;s blog"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p>There are many tools and methods to make <a href=\"https:\/\/www.google.com\/analytics\/\">Google Analytics<\/a> more manageable. <a href=\"https:\/\/tagmanager.google.com\">Google Tag Manager<\/a> is probably the best known of these, and you can find many, many <a href=\"https:\/\/www.simoahava.com\/tags\/google-tag-manager\/\">articles about GTM<\/a> on these pages as well.<\/p>\n<p>However, today I want to tell you about one of the features of Universal Analytics that hasn\u2019t, as far as I know, received too much attention. It\u2019s funny, because at the same time almost everyone uses the feature in the shape of <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/ecommerce\">eCommerce<\/a>, <a href=\"https:\/\/support.google.com\/analytics\/answer\/2558867?hl=en\">enhanced link attribution<\/a>, and <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/cross-domain#autolink\">cross-domain tracking<\/a>. I\u2019m talking, of course, about <strong>Universal Analytics plugins<\/strong>.<\/p>\n<div style=\"aspect-ratio: 1382 \/ 482;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/04\/universal-analytics-plugins.jpg\" title=\"Universal Analytics Plugins\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"482\" width=\"1382\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/04\/universal-analytics-plugins.jpg#ZgotmplZ\" alt=\"Universal Analytics Plugins\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Plugins are JavaScript objects, which you can load and execute using the <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/plugins\">Universal Analytics global object interface<\/a>. This is accessed, by default, using the <code>ga()<\/code> function.<\/p>\n<p>Plugins allow you to do a number of useful things:<\/p>\n<ol>\n<li>\n<p>Decouple tracker object access from JavaScript embedded in the page HTML, allowing you to crete, execute, and maintain often used <code>ga()<\/code> commands in library files instead of directly in the page<\/p>\n<\/li>\n<li>\n<p>Quickly access the tracker object of choice, without having to prefix every command with the tracker name, or to loop through all the existing trackers to find the correct one<\/p>\n<\/li>\n<li>\n<p>Execute the plugin commands <em>synchronously<\/em>, which means you can be 100 % sure that anything the plugin does will be available to commands that come after it in the command queue<\/p>\n<\/li>\n<\/ol>\n<p>All the benefits listed above facilitate a plug-and-play integration between a platform and Google Analytics. If you\u2019re the developer of the platform, you can create a plugin that does most of the legwork, such as assigning a new Custom Dimension with its respective value, and the user only has to load the plugin to reap the benefits.<\/p>\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=\"how-plugins-work\">How plugins work<\/h2>\n<p>Before getting into a technical description of plugins themselves, there\u2019s something we need to clear up about the Universal Analytics tracker object first. Here\u2019s a typical tracking code on a typical website:<\/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&gt;\n  (<span style=\"color:#00a\">function<\/span>(i,s,o,g,r,a,m){i[<span style=\"color:#a50\">'GoogleAnalyticsObject'<\/span>]=r;i[r]=i[r]||<span style=\"color:#00a\">function<\/span>(){\n  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=<span style=\"color:#099\">1<\/span>*<span style=\"color:#00a\">new<\/span> <span style=\"color:#0aa\">Date<\/span>();a=s.createElement(o),\n  m=s.getElementsByTagName(o)[<span style=\"color:#099\">0<\/span>];a.async=<span style=\"color:#099\">1<\/span>;a.src=g;m.parentNode.insertBefore(a,m)\n  })(<span style=\"color:#0aa\">window<\/span>,<span style=\"color:#0aa\">document<\/span>,<span style=\"color:#a50\">'script'<\/span>,<span style=\"color:#a50\">'\/\/www.google-analytics.com\/analytics.js'<\/span>,<span style=\"color:#a50\">'ga'<\/span>);\n\n  ga(<span style=\"color:#a50\">'create'<\/span>, <span style=\"color:#a50\">'UA-1234567-1'<\/span>, <span style=\"color:#a50\">'auto'<\/span>);\n  ga(<span style=\"color:#a50\">'send'<\/span>, <span style=\"color:#a50\">'pageview'<\/span>);\n\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>If you want to understand what the code above does statement by statement, <a href=\"http:\/\/code.stephenmorley.org\/javascript\/understanding-the-google-analytics-tracking-code\/\">this<\/a> and <a href=\"https:\/\/www.thyngster.com\/how-does-the-universal-analytics-snippet-work\/\">this<\/a> are good places to start.<\/p>\n<p>What\u2019s important, however, is that the <em>analytics.js<\/em> library is loaded <em>asynchronously<\/em>. The loading starts when the immediately invoked function expression (IIFE) is executed, but the browser\u2019s JavaScript engine moves right to the two <code>ga()<\/code> commands <em>before the analytics.js library has loaded<\/em>. This means that the two <code>ga()<\/code> calls are not actually interacting with <em>analytics.js<\/em>, but instead they are pushing commands into a <em>command queue<\/em>, which is processed first-in first-out as soon as the library has loaded.<\/p>\n<div style=\"aspect-ratio: 837 \/ 456;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/04\/process.jpg\" title=\"The tracker load process\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"456\" width=\"837\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/04\/process.jpg#ZgotmplZ\" alt=\"The tracker load process\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>This, in turn, has a significant implication on what you can do with the code. Consider the following example:<\/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&gt;\n...the IIFE here...\n\nga(<span style=\"color:#a50\">'create'<\/span>, <span style=\"color:#a50\">'UA-1234567-1'<\/span>, <span style=\"color:#a50\">'auto'<\/span>);\nga(<span style=\"color:#a50\">'send'<\/span>, <span style=\"color:#a50\">'pageview'<\/span>, {\n  <span style=\"color:#a50\">'dimension1'<\/span> : ga.getAll()[<span style=\"color:#099\">0<\/span>].get(<span style=\"color:#a50\">'clientId'<\/span>)\n});\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>If you know your tracker methods, you\u2019ll see that this attempts to send the <strong>clientId<\/strong> of the tracker object as a Custom Dimension with the page view hit.<\/p>\n<p>This code will, however, result in the error: <strong>ga.getAll is not a function<\/strong>. The reason for this error is due to the library not having loaded yet when the JavaScript engine processes the command in the <code>ga()<\/code> call. It\u2019s the <em>analytics.js<\/em> library that sets up the interface for the global object, not the tracking code.<\/p>\n<p>There are two ways to overcome this. You can pass a <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/advanced#pushIt\">callback function as an argument<\/a> to the <code>ga()<\/code> call, and any code within that function will not be executed until the library has loaded. The second method would be to use a <strong>plugin<\/strong>.<\/p>\n<p>When you call the <code>ga('require', 'pluginName')<\/code> method, this request is added to the command queue. When the <em>analytics.js<\/em> library has finally loaded, the command queue will be processed in order. Once the processing reaches this \u2018require\u2019 command, the queue will halt until a \u2018provide\u2019 call with the same plugin name is found in or added to the queue. This means that the following code would work nicely:<\/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&gt;\n...the IIFE here...\n\nga(<span style=\"color:#a50\">'create'<\/span>, <span style=\"color:#a50\">'UA-1234567-1'<\/span>, <span style=\"color:#a50\">'auto'<\/span>);\n<span style=\"color:#aaa;font-style:italic\">\/\/ Load the getClientId plugin, which gets the\n<\/span><span style=\"color:#aaa;font-style:italic\">\/\/ clientId and sets it as dimension1 on following hits\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>ga(<span style=\"color:#a50\">'require'<\/span>, <span style=\"color:#a50\">'getClientId'<\/span>);\nga(<span style=\"color:#a50\">'send'<\/span>, <span style=\"color:#a50\">'pageview'<\/span>);\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>Even though the tracker interface is not available when the \u2018require\u2019 command is added to the queue, the interface <em>will<\/em> be available once the queue is being processed.<\/p>\n<h2 id=\"how-to-create-a-plugin\">How to create a plugin<\/h2>\n<p>Let\u2019s create the <strong>getClientId<\/strong> plugin from the previous chapter. The plugin code itself consists of <strong>two<\/strong> required components:<\/p>\n<ol>\n<li>\n<p>A <strong>constructor<\/strong> that is executed when the plugin is loaded<\/p>\n<\/li>\n<li>\n<p>A <strong>\u2018provide\u2019<\/strong> command that links the constructor with the plugin name<\/p>\n<\/li>\n<\/ol>\n<p>To create the plugin <strong>getClientId<\/strong>, you would need something like the following code loaded 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:#00a\">var<\/span> GetClientId = <span style=\"color:#00a\">function<\/span>(tracker) {\n  tracker.set(<span style=\"color:#a50\">'dimension1'<\/span>, tracker.get(<span style=\"color:#a50\">'clientId'<\/span>));\n};\n<span style=\"color:#00a\">var<\/span> ga = <span style=\"color:#0aa\">window<\/span>[<span style=\"color:#0aa\">window<\/span>[<span style=\"color:#a50\">'GoogleAnalyticsObject'<\/span>] || <span style=\"color:#a50\">'ga'<\/span>];\n<span style=\"color:#00a\">if<\/span> (ga) {\n  ga(<span style=\"color:#a50\">'provide'<\/span>, <span style=\"color:#a50\">'getClientId'<\/span>, GetClientId);\n}\n<\/code><\/pre>\n<\/div>\n<p>The first lines are for the constructor. It\u2019s just a JavaScript function, but it turns into an object constructor  with the <code>ga('require', 'getClientId')<\/code> call, which creates a new object instance of <code>GetClientId<\/code>.<\/p>\n<p>If object-oriented JavaScript confuses you, take a look at the excellent JavaScript track at <a href=\"https:\/\/www.codecademy.com\/catalog\/language\/javascript\">codecademy<\/a>.<\/p>\n<p>Anyway, the tracker object used in the call to the constructor is automatically passed as an argument to the function. This means that you can run commands on the tracker object, and you don\u2019t have to worry about interacting with the right tracker or sending the hits to the right Google Analytics property.<\/p>\n<p>The next lines first make sure that the <code>ga()<\/code> command exists. The <code>ga()<\/code> function is created in the Universal Analytics tracking snippet, so if your plugin code is executed <em>before<\/em> the browser parses the tracking snippet, it might not work.<\/p>\n<p>Finally, the <code>ga('provide', 'pluginName', Constructor)<\/code> command is run so that the plugin can be found with its respective \u2018require\u2019 call.<\/p>\n<p>To briefly recap, here is how plugins are loaded and linked to trackers:<\/p>\n<ol>\n<li>\n<p>The Universal Analytics tracking snippet creates the <code>ga()<\/code> function and the command queue<\/p>\n<\/li>\n<li>\n<p>All function calls to <code>ga()<\/code> are added to this command queue<\/p>\n<\/li>\n<li>\n<p>If you have a plugin, both its \u2018require\u2019 and \u2018provide\u2019 calls will be added to the queue as well<\/p>\n<\/li>\n<li>\n<p>Once the <em>analytics.js<\/em> library has loaded, the commands in the queue are processed in order<\/p>\n<\/li>\n<li>\n<p>If a \u2018require\u2019 command is encountered, the queue processing halts indefinitely, until a \u2018provide\u2019 call with the same plugin name is run<\/p>\n<\/li>\n<li>\n<p>The entire plugin constructor function is executed before queue processing continues<\/p>\n<\/li>\n<\/ol>\n<p>Below is an example of the loading order in action. The plugin \u2018require\u2019 call is between the \u2018create\u2019 and \u2018send\u2019 calls, and the library itself is loaded after the Universal Analytics tracking code snippet. This is to secure that the <code>ga()<\/code> function is created before the plugin.<\/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&gt;\n...the <span style=\"color:#00a\">function<\/span> expression here...\n\nga(<span style=\"color:#a50\">'create'<\/span>, <span style=\"color:#a50\">'UA-1234567-1'<\/span>, <span style=\"color:#a50\">'auto'<\/span>);\nga(<span style=\"color:#a50\">'require'<\/span>, <span style=\"color:#a50\">'getClientId'<\/span>);\nga(<span style=\"color:#a50\">'send'<\/span>, <span style=\"color:#a50\">'pageview'<\/span>);\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;\nscript <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"https:\/\/www.simoahava.com\/scripts\/getClientId.js\"<\/span> <span style=\"color:#1e90ff\">async<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>Note that the \u2018require\u2019 command waits for the respective \u2018provide\u2019 command <em>indefinitely<\/em>. This means that if you misspell the plugin name, or if you only have the \u2018require\u2019 command there for some reason, the queue processing <em>will not proceed<\/em>. So try to avoid breaking your analytics implementation, please!<\/p>\n<h2 id=\"example-simoplugin-library\">Example: SimoPlugin library<\/h2>\n<p>Here\u2019s an example of a plugin I might be tempted to use over and over again. In it, I have two special features:<\/p>\n<ol>\n<li>\n<p>A <strong>generic event pusher<\/strong>, which I can use with all my trackers to send events to their respective properties<\/p>\n<\/li>\n<li>\n<p>A <strong>hit duplicator<\/strong>, which duplicates the hit to the Universal Analytics collection endpoint, and sends it as an HTTP request to any custom endpoint of my choice<\/p>\n<\/li>\n<\/ol>\n<p>I\u2019m storing the plugin in a file called <strong>simoPlugin.js<\/strong>, which I then load asynchronously after my tracking 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-html\" data-lang=\"html\">script&gt;\n...the IIFE here...\n\nga(<span style=\"color:#a50\">'create'<\/span>, <span style=\"color:#a50\">'UA-1234567-1'<\/span>, <span style=\"color:#a50\">'auto'<\/span>);\nga(<span style=\"color:#a50\">'create'<\/span>, <span style=\"color:#a50\">'UA-1234567-2'<\/span>, <span style=\"color:#a50\">'auto'<\/span>, {<span style=\"color:#a50\">'name'<\/span> : <span style=\"color:#a50\">'rollup'<\/span>});\nga(<span style=\"color:#a50\">'require'<\/span>, <span style=\"color:#a50\">'simoPlugin'<\/span>);\nga(<span style=\"color:#a50\">'rollup.require'<\/span>, <span style=\"color:#a50\">'simoPlugin'<\/span>);\nga(<span style=\"color:#a50\">'send'<\/span>, <span style=\"color:#a50\">'pageview'<\/span>);\nga(<span style=\"color:#a50\">'rollup.send'<\/span>, <span style=\"color:#a50\">'pageview'<\/span>);\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;\nscript <span style=\"color:#1e90ff\">src<\/span>=<span style=\"color:#a50\">\"https:\/\/www.simoahava.com\/scripts\/simoPlugin.js\"<\/span> <span style=\"color:#1e90ff\">async<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>As you can see, I have my normal tracker and a tracker with the name <strong>rollup<\/strong>, and I\u2019m loading the plugin for both trackers using the typical <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/advanced#multipletrackers\">multiple tracker<\/a> syntax.<\/p>\n<p>The way the <strong>hit duplicator<\/strong> works is that whenever a \u2018send\u2019 command is used, e.g. <code>ga('send', 'pageview')<\/code>, the exact payload to the Universal Analytics endpoint is copied and sent to a (fictional) endpoint of mine at _<a href=\"http:\/\/process.simoahava.com\/collect_:\">http:\/\/process.simoahava.com\/collect_:<\/a><\/p>\n<div style=\"aspect-ratio: 1454 \/ 294;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/04\/local-copy.jpg\" title=\"Hit duplication\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"294\" width=\"1454\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/04\/local-copy.jpg#ZgotmplZ\" alt=\"Hit duplication\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>By duplicating hits like this, you can create your own data collection mechanism. You can even use a cloud endpoint, which will give you a lot more processing power and scale. You might even use this to overcome the <a href=\"https:\/\/www.simoahava.com\/analytics\/the-schema-conspiracy\/\">schema conspiracy<\/a> I\u2019ve been ranting about before.<\/p>\n<p>The <strong>generic event pusher<\/strong> works by sending a custom event object to a plugin method called <code>trackEvent<\/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\">ga(<span style=\"color:#a50\">'simoPlugin:trackEvent'<\/span>, {\n  <span style=\"color:#a50\">'cat'<\/span> : <span style=\"color:#a50\">'Link Click'<\/span>, \n  <span style=\"color:#a50\">'act'<\/span> : <span style=\"color:#a50\">'Outbound'<\/span>, \n  <span style=\"color:#a50\">'lab'<\/span> : <span style=\"color:#a50\">'http:\/\/www.google.com'<\/span>, \n  <span style=\"color:#a50\">'di'<\/span> : <span style=\"color:#099\">4<\/span>, \n  <span style=\"color:#a50\">'dv'<\/span> : <span style=\"color:#0aa\">document<\/span>.location.pathname\n});\n<\/code><\/pre>\n<\/div>\n<p>As you can see, an object literal is passed as the second argument of the <code>ga()<\/code> call. This argument, in turn, is passed to the <code>trackEvent<\/code> method in the plugin code. The method takes the arguments, makes sure no undefined fields are sent, and pushes an event hit to the property associated with the tracker that was used to call the plugin method. If I wanted to send the call to my <em>rollup<\/em> tracker, I would have used the syntax <code>ga('rollup.simoPlugin:trackEvent')<\/code>.<\/p>\n<h3 id=\"simoplugin-code\">simoPlugin code<\/h3>\n<p>The code stored in the <strong>simoPlugin.js<\/strong> library looks 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\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Assign the ga variable to the Google Analytics global function\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> ga = <span style=\"color:#0aa\">window<\/span>[<span style=\"color:#0aa\">window<\/span>[<span style=\"color:#a50\">'GoogleAnalyticsObject'<\/span>] || <span style=\"color:#a50\">'ga'<\/span>];\n\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Helper function for registering the Plugin\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> providePlugin = <span style=\"color:#00a\">function<\/span>(pluginName, pluginConstructor) {\n    <span style=\"color:#00a\">if<\/span> (ga) { \n      ga(<span style=\"color:#a50\">'provide'<\/span>, pluginName, pluginConstructor);\n    }\n  };\n  \n  <span style=\"color:#aaa;font-style:italic\">\/\/ Constructor for simoPlugin\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#aaa;font-style:italic\">\/\/ Copies payload to custom host\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> SimoPlugin = <span style=\"color:#00a\">function<\/span>(tracker) {\n    <span style=\"color:#00a\">this<\/span>.tracker = tracker;\n    \n    <span style=\"color:#aaa;font-style:italic\">\/\/ Copy the original hit dispatch function\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> originalSendHitTask = <span style=\"color:#00a\">this<\/span>.tracker.get(<span style=\"color:#a50\">'sendHitTask'<\/span>);\n    \n    <span style=\"color:#aaa;font-style:italic\">\/\/ Modify the existing hit dispatcher to send a local copy of the hit\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">this<\/span>.tracker.set(<span style=\"color:#a50\">'sendHitTask'<\/span>, <span style=\"color:#00a\">function<\/span>(model) {\n      originalSendHitTask(model); <span style=\"color:#aaa;font-style:italic\">\/\/ Send the original hit as usual\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>      <span style=\"color:#00a\">var<\/span> xhr = <span style=\"color:#00a\">new<\/span> XMLHttpRequest();\n      xhr.open(<span style=\"color:#a50\">'POST'<\/span>, <span style=\"color:#a50\">'http:\/\/process.simoahava.com\/collect'<\/span>, <span style=\"color:#00a\">true<\/span>);\n      xhr.send(model.get(<span style=\"color:#a50\">'hitPayload'<\/span>));\n    });\n  };\n  \n  <span style=\"color:#aaa;font-style:italic\">\/\/ Set up a generic event dispatcher\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  SimoPlugin.prototype.trackEvent = <span style=\"color:#00a\">function<\/span>(evt) {\n    <span style=\"color:#00a\">var<\/span> c = evt[<span style=\"color:#a50\">'cat'<\/span>];\n    <span style=\"color:#00a\">var<\/span> a = evt[<span style=\"color:#a50\">'act'<\/span>];\n    <span style=\"color:#00a\">var<\/span> l = evt[<span style=\"color:#a50\">'lab'<\/span>] || <span style=\"color:#00a\">undefined<\/span>;\n    <span style=\"color:#00a\">var<\/span> v = evt[<span style=\"color:#a50\">'val'<\/span>] || <span style=\"color:#00a\">undefined<\/span>;\n    <span style=\"color:#00a\">var<\/span> x = {};\n    x[<span style=\"color:#a50\">'nonInteraction'<\/span>] = evt[<span style=\"color:#a50\">'ni'<\/span>] || <span style=\"color:#00a\">false<\/span>;\n    <span style=\"color:#00a\">if<\/span> (evt[<span style=\"color:#a50\">'di'<\/span>]) {\n      x[<span style=\"color:#a50\">'dimension'<\/span> + evt[<span style=\"color:#a50\">'di'<\/span>]] = evt[<span style=\"color:#a50\">'dv'<\/span>] || <span style=\"color:#00a\">undefined<\/span>;\n    }\n    <span style=\"color:#00a\">this<\/span>.tracker.send(<span style=\"color:#a50\">'event'<\/span>, c, a, l, v, x);\n  };\n  \n  providePlugin(<span style=\"color:#a50\">'simoPlugin'<\/span>, SimoPlugin);\n})();\n<\/code><\/pre>\n<\/div>\n<p>First things first: the whole thing is wrapped in an <em>immediately invoked function expression<\/em>. This is a good habit in general, since it will scope all variables within to function scope, and thus you\u2019ll avoid polluting the global namespace. Here\u2019s good overview of why IIFEs rock: <a href=\"http:\/\/gregfranko.com\/blog\/i-love-my-iife\/\">I Love My IIFE &#8211; Greg Frank<\/a>.<\/p>\n<p>The next few lines are for making the plugin loader more generic. Since it\u2019s possible to <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/advanced#renaming\">change the global function name<\/a> in the <em>analytics.js<\/em> tracking code, we\u2019ll need to make sure the plugin loader works even if the function name is no longer <code>ga<\/code>.<\/p>\n<p>The <code>providePlugin<\/code> is a generic helper function which is largely redundant, but it will provide useful if you\u2019re loading multiple plugins in the same library.<\/p>\n<h3 id=\"the-constructor\">The constructor<\/h3>\n<p>We create the constructor function in these lines:<\/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> SimoPlugin = <span style=\"color:#00a\">function<\/span>(tracker) {\n  <span style=\"color:#00a\">this<\/span>.tracker = tracker;\n    \n  <span style=\"color:#aaa;font-style:italic\">\/\/ Copy the original hit dispatch function\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> originalSendHitTask = <span style=\"color:#00a\">this<\/span>.tracker.get(<span style=\"color:#a50\">'sendHitTask'<\/span>);\n    \n  <span style=\"color:#aaa;font-style:italic\">\/\/ Modify the existing hit dispatcher to send a local copy of the hit\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">this<\/span>.tracker.set(<span style=\"color:#a50\">'sendHitTask'<\/span>, <span style=\"color:#00a\">function<\/span>(model) {\n    originalSendHitTask(model); <span style=\"color:#aaa;font-style:italic\">\/\/ Send the original hit as usual\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> xhr = <span style=\"color:#00a\">new<\/span> XMLHttpRequest();\n    xhr.open(<span style=\"color:#a50\">'POST'<\/span>, <span style=\"color:#a50\">'http:\/\/process.simoahava.com\/collect'<\/span>, <span style=\"color:#00a\">true<\/span>);\n    xhr.send(model.get(<span style=\"color:#a50\">'hitPayload'<\/span>));\n  });\n};\n<\/code><\/pre>\n<\/div>\n<p>As you can see, the first argument to the function will be the tracker object used to load the plugin. This means that we can manipulate and use this tracker object interface without having to worry about accidentally sending hits to wrong GA properties!<\/p>\n<p>I use <code>this.tracker = tracker;<\/code> to store a reference to the tracker object into each instance of the plugin created with this constructor. This is why commands like <code>ga('simoPlugin:trackEvent')<\/code> and <code>ga('rollup.simoPlugin:trackEvent')<\/code> access a different tracker object. They both have their own, unique bindings of <code>this<\/code>, and thus they both have their own, unique tracker object references.<\/p>\n<p>The next line accesses the <strong>sendHitTask<\/strong> <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/tasks\">property of the tracker object<\/a>. Whenever a \u2018send\u2019 command is used with the Universal Analytics global function, a series of tasks are executed. <strong>sendHitTask<\/strong> is one of these, and it is used to send the hit payload to the Universal Analytics collection endpoint.<\/p>\n<p>The last call in the block is for updating the <strong>sendHitTask<\/strong> task in the tracker. This update uses the original <strong>sendHitTask<\/strong> (now stored in a variable called <code>originalSendHitTask<\/code>), and sends the payload to the Universal Analytics collection endpoint as before. The next three lines create a new HTTP request to the endpoint of your choice. The payload of this request is the exactly same payload that is sent to Universal Analytics.<\/p>\n<p>By using this code, you will be able to create a perfect copy of the hit sent to Universal Analytics, and you can send this copy anywhere you want, such as a local hit processor, or a custom endpoint in a cloud server, for example.<\/p>\n<p>Because this code is in the constructor, it is automatically applied to <strong>all<\/strong> \u2018send\u2019 commands that take place on the page after the plugin has been loaded.<\/p>\n<h3 id=\"the-event-pusher\">The event pusher<\/h3>\n<p>The event pusher is defined as a method of the <code>SimoPlugin<\/code> object prototype. The reason we\u2019re applying it to the prototype is because we want it to be available to all instances created with the <code>SimoPlugin<\/code> constructor. If we\u2019d leave the <code>prototype<\/code> object out of the declaration, the <code>trackEvent<\/code> method would be added to an object literal called <code>SimoPlugin<\/code>, and not the object prototype. This means that the instances created from this prototype would not be able to use that method.<\/p>\n<p>Again, if this is confusing, be sure to read up on object-oriented JavaScript. It\u2019s interesting stuff, and it really shows what a complex and powerful programming language JavaScript is!<\/p>\n<p>The event pusher code looked 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\">SimoPlugin.prototype.trackEvent = <span style=\"color:#00a\">function<\/span>(evt) {\n  <span style=\"color:#00a\">var<\/span> c = evt[<span style=\"color:#a50\">'cat'<\/span>];\n  <span style=\"color:#00a\">var<\/span> a = evt[<span style=\"color:#a50\">'act'<\/span>];\n  <span style=\"color:#00a\">var<\/span> l = evt[<span style=\"color:#a50\">'lab'<\/span>] || <span style=\"color:#00a\">undefined<\/span>;\n  <span style=\"color:#00a\">var<\/span> v = evt[<span style=\"color:#a50\">'val'<\/span>] || <span style=\"color:#00a\">undefined<\/span>;\n  <span style=\"color:#00a\">var<\/span> x = {};\n  x[<span style=\"color:#a50\">'nonInteraction'<\/span>] = evt[<span style=\"color:#a50\">'ni'<\/span>] || <span style=\"color:#00a\">false<\/span>;\n  <span style=\"color:#00a\">if<\/span> (evt[<span style=\"color:#a50\">'di'<\/span>]) {\n    x[<span style=\"color:#a50\">'dimension'<\/span> + evt[<span style=\"color:#a50\">'di'<\/span>]] = evt[<span style=\"color:#a50\">'dv'<\/span>] || <span style=\"color:#00a\">undefined<\/span>;\n  }\n  <span style=\"color:#00a\">this<\/span>.tracker.send(<span style=\"color:#a50\">'event'<\/span>, c, a, l, v, x);\n};\n<\/code><\/pre>\n<\/div>\n<p>This code takes an object as an argument. This object is sent with the <code>ga()<\/code> command when the method is invoked:<\/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\">ga(<span style=\"color:#a50\">'simoPlugin:trackEvent'<\/span>, {\n  <span style=\"color:#a50\">'cat'<\/span> : <span style=\"color:#a50\">'category'<\/span>,\n  <span style=\"color:#a50\">'act'<\/span> : <span style=\"color:#a50\">'action'<\/span>,\n  <span style=\"color:#a50\">'lab'<\/span> : <span style=\"color:#a50\">'label'<\/span>,\n  <span style=\"color:#a50\">'val'<\/span> : <span style=\"color:#099\">1<\/span>,\n  <span style=\"color:#a50\">'ni'<\/span> : <span style=\"color:#00a\">false<\/span>,\n  <span style=\"color:#a50\">'di'<\/span> : <span style=\"color:#099\">1<\/span>,\n  <span style=\"color:#a50\">'dv'<\/span> : <span style=\"color:#a50\">'dimensionValue'<\/span>\n});\n<\/code><\/pre>\n<\/div>\n<p>There are fields for Category, Action, Label, and Value, and I also let you determine whether the hit is non-interaction or not. Finally, you can also add one dimension with the index number and value exposed in the parameters.<\/p>\n<p>Because Category and Action are required fields for events, the code will fail if these are not in the object. All the other fields can be left out, which is why I have them resolve to <em>undefined<\/em> if they don\u2019t exist in the event object. The exception is the <strong>nonInteraction<\/strong> field, which defaults to <em>false<\/em>.<\/p>\n<p>Using this generic event pusher, it\u2019s pretty trivial to send simple AND complex events to Universal Analytics.<\/p>\n<p>The final line, <code>this.tracker.send()<\/code>, sends the event using the tracker object\u2019s <code>send()<\/code> method. As you can see, we\u2019re using <code>this.tracker<\/code>, which accesses the interface of the tracker object used to call the method. The beauty of object-oriented JavaScript, right here ladies and gentlemen! If we didn\u2019t use the power of object instances like this, we\u2019d need to loop through all the trackers on the page to find the one we want to use. Way too complex!<\/p>\n<h2 id=\"platform-integrations\">Platform integrations<\/h2>\n<p>Well, if the event pusher didn\u2019t persuade you with its potential, and if you\u2019re left unimpressed by the hit duplicator, another great idea for plugins is to integrate a SaaS platform and Google Analytics together.<\/p>\n<p>For example, let\u2019s say you have a platform through which you can create a new Custom Dimension in a Universal Analytics property, and then you can populate it with some value. This would happen programmatically, and the platform would use the <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/config\/mgmt\/v3\/\">Google Analytics Management API<\/a> to create the Custom Dimension.<\/p>\n<p>Once the dimension is created, you\u2019d dynamically generate the JavaScript plugin library to include these programmatically created Custom Dimensions. Then you use the plugin commands to send hits to the trackers, using the correct Custom Dimensions.<\/p>\n<div style=\"aspect-ratio: 633 \/ 404;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/04\/integration.jpg\" title=\"Platform integration with plugin\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"404\" width=\"633\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/04\/integration.jpg#ZgotmplZ\" alt=\"Platform integration with plugin\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>This makes the integration between the platform and the website very plug-and-play, and you don\u2019t need to ask the users to look up the correct dimension number, add it to the inline code, and risk some silly misunderstanding ruining the integration.<\/p>\n<p>It\u2019s such an elegant way of associating a website with your platform with just two lines of code at best (one for loading the library, and one for the <code>ga('require', 'pluginName')<\/code> call).<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>Plugins are an excellent way of associating often made calls with their respective tracker objects.<\/p>\n<p>Also, they allow you to decouple all of the Universal Analytics commands from inline code. This allows you to write complex handlers for these commands without polluting the page template.<\/p>\n<p>Plugins are, however, quite an advanced use case for data collection. They require a very good understanding of JavaScript and of how the Universal Analytics library works.<\/p>\n<p>Especially if you\u2019re working with platform integrations and want to minimize the amount of work that users willing to implement the plugin need to do, I strongly recommend talking to your developers about creating a custom plugin for the integration.<\/p>\n<p>Unfortunately, plugins are not supported by the Google Tag Manager Universal Analytics tag template yet, so you might have to use a Custom HTML Tag to load plugins with GTM. See <a href=\"https:\/\/www.simoahava.com\/analytics\/improve-data-collection-with-four-custom-dimensions\/\">this article<\/a> for inspiration.<\/p>\n<\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>There are many tools and methods to make Google Analytics more manageable. Google Tag Manager is probably the best known of these, and you can find many, many articles about GTM on these pages as well. However, today I want to tell you about one of the features of Universal Analytics that hasn\u2019t, as far [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":147674,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[27402,12765,3767,11385,19648,27401,1260],"dealstore":[],"offerexpiration":[],"class_list":["post-147673","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-ahavas","tag-analytics","tag-blog","tag-explained","tag-plugins","tag-simo","tag-universal"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Universal Analytics Plugins Explained | Simo Ahava&#039;s blog - 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=147673\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Universal Analytics Plugins Explained | Simo Ahava&#039;s blog - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"There are many tools and methods to make Google Analytics more manageable. Google Tag Manager is probably the best known of these, and you can find many, many articles about GTM on these pages as well. However, today I want to tell you about one of the features of Universal Analytics that hasn\u2019t, as far [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=147673\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-03-21T12:30:12+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/universal-analytics-plugins.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1382\" \/>\n\t<meta property=\"og:image:height\" content=\"482\" \/>\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=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=147673#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=147673\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"Universal Analytics Plugins Explained | Simo Ahava&#8217;s blog\",\"datePublished\":\"2025-03-21T12:30:12+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=147673\"},\"wordCount\":2519,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=147673#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/universal-analytics-plugins.jpg\",\"keywords\":[\"Ahavas\",\"Analytics\",\"Blog\",\"Explained\",\"Plugins\",\"Simo\",\"Universal\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=147673#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=147673\",\"url\":\"https:\/\/fivemor.com\/?p=147673\",\"name\":\"Universal Analytics Plugins Explained | Simo Ahava's blog - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=147673#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=147673#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/universal-analytics-plugins.jpg\",\"datePublished\":\"2025-03-21T12:30:12+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=147673#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=147673\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=147673#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/universal-analytics-plugins.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/universal-analytics-plugins.jpg\",\"width\":1382,\"height\":482},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=147673#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Universal Analytics Plugins Explained | Simo Ahava&#8217;s blog\"}]},{\"@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":"Universal Analytics Plugins Explained | Simo Ahava's blog - 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=147673","og_locale":"en_US","og_type":"article","og_title":"Universal Analytics Plugins Explained | Simo Ahava's blog - Som2ny Network","og_description":"There are many tools and methods to make Google Analytics more manageable. Google Tag Manager is probably the best known of these, and you can find many, many articles about GTM on these pages as well. However, today I want to tell you about one of the features of Universal Analytics that hasn\u2019t, as far [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=147673","og_site_name":"Som2ny Network","article_published_time":"2025-03-21T12:30:12+00:00","og_image":[{"width":1382,"height":482,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/universal-analytics-plugins.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=147673#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=147673"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"Universal Analytics Plugins Explained | Simo Ahava&#8217;s blog","datePublished":"2025-03-21T12:30:12+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=147673"},"wordCount":2519,"commentCount":0,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=147673#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/universal-analytics-plugins.jpg","keywords":["Ahavas","Analytics","Blog","Explained","Plugins","Simo","Universal"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=147673#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=147673","url":"https:\/\/fivemor.com\/?p=147673","name":"Universal Analytics Plugins Explained | Simo Ahava's blog - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=147673#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=147673#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/universal-analytics-plugins.jpg","datePublished":"2025-03-21T12:30:12+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=147673#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=147673"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=147673#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/universal-analytics-plugins.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/universal-analytics-plugins.jpg","width":1382,"height":482},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=147673#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"Universal Analytics Plugins Explained | Simo Ahava&#8217;s blog"}]},{"@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\/147673","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=147673"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/147673\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/147674"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=147673"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=147673"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=147673"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=147673"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=147673"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}