{"id":109975,"date":"2025-02-25T22:37:34","date_gmt":"2025-02-25T22:37:34","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/customtask-the-guide-simo-ahavas-blog\/"},"modified":"2025-02-25T22:37:34","modified_gmt":"2025-02-25T22:37:34","slug":"customtask-the-guide-simo-ahavas-blog","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=109975","title":{"rendered":"customTask &#8211; The Guide | Simo Ahava&#8217;s blog"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p><em>Last updated 4 September 2018<\/em><\/p>\n<p>If you have been reading my blog articles over the past year, you might have noticed a disturbing trend. I\u2019ve published <a href=\"https:\/\/www.simoahava.com\/tags\/customtask\/\">9 articles on <code>customTask<\/code><\/a> since the API was released. It might not sound like much, but I can\u2019t think of a single feature in <a href=\"https:\/\/analytics.google.com\/\">Google Analytics<\/a> or <a href=\"https:\/\/tagmanager.google.com\/\">Google Tag Manager<\/a> that has so completely convinced me of its usefulness in such a short time.<\/p>\n<p>The <code>customTask<\/code> API is a feature of the <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/tasks\">Universal Analytics library<\/a> (used by Google Tag Manager\u2019s tags, too). It lets you <code>get<\/code> and <code>set<\/code> values from and to the (Measurement Protocol) hit as it\u2019s being generated. This is really useful for a couple of reasons, which I\u2019ve covered in the previous articles, but I\u2019ll go over them briefly in the beginning of this guide, too.<\/p>\n<div style=\"aspect-ratio: 874 \/ 485;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/02\/customtask-the-guide.jpg\" title=\"customTask - The Guide\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"485\" width=\"874\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/02\/customtask-the-guide.jpg#ZgotmplZ\" alt=\"customTask - The Guide\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Suffice to say that especially for Google Tag Manager, <code>customTask<\/code> adds a lot of value. With GTM, it\u2019s always been quite difficult to access the hit-building process when using tag templates. Luckily, <code>customTask<\/code> offers a solution to this problem, and at least for this particular developer it\u2019s opened a whole new world of Google Analytics customization.<\/p>\n<p>However, in spite of writing all those articles on <code>customTask<\/code>, I recently realized that I never actually took the time to explain more thoroughly how it works. Also, I haven\u2019t yet shared solutions for combining multiple <code>customTask<\/code> tricks in a single tag. This guide seeks to address these points.<\/p>\n<blockquote>\n<p>Be sure to check out my <a href=\"https:\/\/www.simoahava.com\/tools\/customtask-builder\/\">customTask Builder<\/a> tool as well &#8211; it will help you compile the necessary JavaScript for <code>customTask<\/code> to run in your setup without conflicts!<\/p>\n<\/blockquote>\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-tasks-work\">How Tasks work<\/h2>\n<p>When you run the <code>ga('send', 'pageview')<\/code> command either directly in your site JavaScript or indirectly via Google Tag Manager\u2019s Google Analytics tags, you actually request that the Universal Analytics JavaScript library (analytics.js) compile an HTTP request to the Google Analytics servers.<\/p>\n<p>The endpoint to which the hits are sent is typically <code>\/collect<\/code> on the Google Analytics collector domain. The process of building and sending hits to the GA servers is also known as <strong>Measurement Protocol<\/strong> (MP). In fact, MP is the underlying process used by <strong>all<\/strong> GA tracking mechanisms, be they the <code>ga('send'...)<\/code> JavaScript SDK, Google Tag Manager\u2019s GA tags, native SDKs for Android and iOS, and custom-built HTTP requests from point-of-sales systems, for example.<\/p>\n<div style=\"aspect-ratio: 1909 \/ 723;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/02\/tracker-process.jpg\" title=\"Tracker process\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"723\" width=\"1909\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/02\/tracker-process.jpg#ZgotmplZ\" alt=\"Tracker process\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>When you use the JavaScript SDK, either via <code>ga('send', 'pageview')<\/code> or the Google Analytics tags in GTM, you are thus initiating a sequence of processes, where the final product is the actual MP request to Google Analytics. This sequence comprises a number of <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/tasks\"><strong>tasks<\/strong><\/a>, of which <code>customTask<\/code> is the first one that is executed.<\/p>\n<p>Here\u2019s a quick recap of what each task does, listed in the order they are applied to the hit.<\/p>\n<table>\n<thead>\n<tr>\n<th>Task<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>customTask<\/strong><\/td>\n<td>No functionality of its own, but can be used to manipulate the <code>model<\/code> object before it is processed by the other tasks.<\/td>\n<\/tr>\n<tr>\n<td><strong>previewTask<\/strong><\/td>\n<td>If the request is generated from the pageview of a \u201cTop Sites\u201d thumbnail in Safari, abort the hit.<\/td>\n<\/tr>\n<tr>\n<td><strong>checkProtocolTask<\/strong><\/td>\n<td>Aborts the request if the page protocol is not valid (<strong>http<\/strong> or <strong>https<\/strong>).<\/td>\n<\/tr>\n<tr>\n<td><strong>validationTask<\/strong><\/td>\n<td>Checks if the fields in the request have valid and expected values. Aborts the request if this is not the case (e.g. trying to send a string as the Event Value).<\/td>\n<\/tr>\n<tr>\n<td><strong>historyImportTask<\/strong><\/td>\n<td>If there is still legacy tracking running on the site, this task imports information from the old GA library cookies into Universal Analytics. Very useful if the site is migrating to Universal Analytics.<\/td>\n<\/tr>\n<tr>\n<td><strong>samplerTask<\/strong><\/td>\n<td>If you\u2019ve decided to <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/field-reference#sampleRate\">manually sample<\/a> the users to stay within Google Analytics\u2019 processing limits, this task aborts the request if the user is sampled out of data collection.<\/td>\n<\/tr>\n<tr>\n<td><strong>buildHitTask<\/strong><\/td>\n<td>Generates the <code>hitPayload<\/code> string, which is essentially the list of query parameters and their values passed to the Measurement Protocol request.<\/td>\n<\/tr>\n<tr>\n<td><strong>sendHitTask<\/strong><\/td>\n<td>Sends the <code>hitPayload<\/code> in a Measurement Protocol request to the GA servers.<\/td>\n<\/tr>\n<tr>\n<td><strong>timingTask<\/strong><\/td>\n<td>If you are automatically sampling pages for page speed measurements, this task sends the timing hit to Google Analytics.<\/td>\n<\/tr>\n<tr>\n<td><strong>displayFeaturesTask<\/strong><\/td>\n<td>If you have enabled display features in GA settings, this task compiles the request to the DoubleClick servers.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Each tasks receives the <code>model<\/code> object as a parameter. The <code>model<\/code> object contains all the fields that have been set in the tracker, as well as any enhancements applied in the tasks themselves.<\/p>\n<p>The beauty of <code>customTask<\/code> is that because it runs before any of the other tasks, you can use it to overwrite behavior of these other tasks. For example, if you want to <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/gtmtips-deploy-gtm-chrome-extension\/\">run Google Analytics locally or in a Chrome Extension<\/a>, you\u2019ll need to make sure <code>checkProtocolTask<\/code> is never run, because it aborts the hit builder if the page protocol is not <strong>http<\/strong> or <strong>https<\/strong>. The <code>customTask<\/code> would look 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\">var<\/span> customTask = <span style=\"color:#00a\">function<\/span>(model) {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Prevent checkProtocolTask from running\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  model.set(<span style=\"color:#a50\">'checkProtocolTask'<\/span>, <span style=\"color:#00a\">null<\/span>);\n};\n<\/code><\/pre>\n<\/div>\n<p>As you can see, the task is actually a field in the <code>model<\/code> object that you can manipulate just as you can manipulate any other field in the <code>model<\/code>. For example, if you want to grab the tracking ID (UA-XXXXXX-Y) and send it in the Custom Dimension with index 15, you can use the following <code>customTask<\/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:#00a\">var<\/span> customTask = <span style=\"color:#00a\">function<\/span>(model) {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Get the tracking ID from the model object\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> trackingId = model.get(<span style=\"color:#a50\">'trackingId'<\/span>);\n  \n  <span style=\"color:#aaa;font-style:italic\">\/\/ Set the tracking ID to Custom Dimension 15\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  model.set(<span style=\"color:#a50\">'dimension15'<\/span>, trackingId);\n};\n<\/code><\/pre>\n<\/div>\n<p>To see what fields are available in the model object, check <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/field-reference\">this developer documentation<\/a>. Note that it\u2019s not complete, since it\u2019s missing all the tasks.<\/p>\n<p>By running these <code>model<\/code> interactions with <code>customTask<\/code>, you have a lot of control over how the task sequence is run. Especially with Google Tag Manager, it would be difficult to run any complicated logic for when and how to manipulate <code>sendHitTask<\/code>, if you applied it directly to the tag as a field.<\/p>\n<h2 id=\"how-to-add-customtask-to-your-hits\">How to add <code>customTask<\/code> to your hits<\/h2>\n<p>To add <code>customTask<\/code> to your <strong>Google Tag Manager<\/strong> tags, you need to create a Custom JavaScript variable which returns the <code>customTask<\/code> method in the variable body. Practically all my <code>customTask<\/code> articles show examples of what this Custom JavaScript variable looks like.<\/p>\n<p>When you are ready to add the variable to your tags, you can do it either via a <a href=\"https:\/\/www.simoahava.com\/analytics\/google-analytics-settings-variable-in-gtm\/\">Google Analytics Settings variable (recommended)<\/a>, or by <a href=\"https:\/\/www.simoahava.com\/analytics\/edit-google-analytics-tag-settings\/\">overriding the tag settings<\/a> directly.<\/p>\n<p>You need to scroll down to <strong>Fields to set<\/strong>, and add a new field which looks like this:<\/p>\n<div style=\"aspect-ratio: 1766 \/ 468;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/09\/set-customtask-gtm.jpg\" title=\"Set customTask in GTM\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"468\" width=\"1766\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/09\/set-customtask-gtm.jpg#ZgotmplZ\" alt=\"Set customTask in GTM\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>If using the on-page Universal Analytics (analytics.js) snippet, you add the <code>customTask<\/code> like this, for 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-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">var<\/span> _customTask = <span style=\"color:#00a\">function<\/span>() {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Set Client ID to Custom Dimension 199\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">function<\/span>(customTaskModel) {\n    customTaskModel.set(<span style=\"color:#a50\">'dimension199'<\/span>, customTaskModel.get(<span style=\"color:#a50\">'clientId'<\/span>));\n  };\n};\n\nga(<span style=\"color:#a50\">'create'<\/span>, <span style=\"color:#a50\">'UA-12345-1'<\/span>);\nga(<span style=\"color:#a50\">'set'<\/span>, <span style=\"color:#a50\">'customTask'<\/span>, _customTask());\nga(<span style=\"color:#a50\">'send'<\/span>, <span style=\"color:#a50\">'pageview'<\/span>);\n<\/code><\/pre>\n<\/div>\n<p>Do note that you can <strong>only set one <code>customTask<\/code> per tracker \/ hit \/ tag<\/strong>. If you want to add more than one \u201ctrick\u201d to the <code>customTask<\/code> function, you need to write the JavaScript that combines all the different solutions into one coherent whole.<\/p>\n<p>Or, you can use my <a href=\"https:\/\/www.simoahava.com\/tools\/customtask-builder\/\"><strong>customTask Builder tool<\/strong><\/a>, which does the dirty work for you.<\/p>\n<h2 id=\"things-you-can-do-with-customtask\">Things you can do with <code>customTask<\/code><\/h2>\n<p>As written above, <code>customTask<\/code> is special for two reasons.<\/p>\n<ol>\n<li>\n<p>It has no special functionality of its own. A task queue can and will run perfectly without <code>customTask<\/code> defined.<\/p>\n<\/li>\n<li>\n<p>It runs before any other task, meaning you have full control over how the queue is processed.<\/p>\n<\/li>\n<\/ol>\n<p>With these two things in mind, here\u2019s the list of all the <code>customTask<\/code> tricks I\u2019ve written about, with a description of what makes them special.<\/p>\n<h3 id=\"1-set-client-id-as-a-custom-dimension\">1. Set Client ID as a Custom Dimension<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/use-customtask-access-tracker-values-google-tag-manager\/\">#GTMTips: Use customTask To Access Tracker Values In Google Tag Manager<\/a>.<\/p>\n<p>This is one of the simpler tricks. It doesn\u2019t manipulate the task queue itself at all, it simply <em>gets<\/em> the Client ID from the model object, and then <em>sets<\/em> it as the value of the specified Custom Dimension.<\/p>\n<p>It\u2019s an elegant solution to a difficult problem. Without <code>customTask<\/code>, getting and setting the Client ID in a Google Analytics tag was difficult. If the tag is run for a first-time visitor who hasn\u2019t received a Client ID yet, the actual <code>clientId<\/code> field is not available when the regular tag fields are resolved. A typical hack for this solution was to fetch the Client ID by creating a <a href=\"https:\/\/www.simoahava.com\/analytics\/access-the-tracker-object-in-your-page-view-tag\/\">dummy tracker<\/a> or by sending the Client ID with an Event tag that fired after the Pageview.<\/p>\n<p>But with <code>customTask<\/code>, there\u2019s no need for such unorthodox methods.<\/p>\n<h3 id=\"2-duplicate-google-analytics-tags-to-more-than-one-property\">2. Duplicate Google Analytics tags to more than one property<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/send-google-analytics-tag-multiple-properties\/\">#GTMTips: Send Google Analytics Tag To Multiple Properties<\/a>.<\/p>\n<p>This is <code>customTask<\/code> at its purest. The <code>customTask<\/code> function first stores a reference to <code>sendHitTask<\/code> in a global variable, after which it overwrites <code>sendHitTask<\/code> in the current model object with the duplicator code.<\/p>\n<p>The duplicator first lets the original hit fire to GA, after which it replaces the Tracking ID in the <code>hitPayload<\/code> with the Tracking ID of the second property. Then, the global <code>sendHitTask<\/code> is invoked again, and the hit is sent to the second property with an identical payload.<\/p>\n<p><strong>Note!<\/strong> The reason the reference to <code>sendHitTask<\/code> is stored in a global variable is to avoid issues with field multiplication. Let\u2019s say you always use this to get the original <code>sendHitTask<\/code> reference:<\/p>\n<p><code>var originalSendTask = model.get('sendHitTask');<\/code><\/p>\n<p>Each time this <code>customTask<\/code> code is run, it will get a reference to what is stored in the model object\u2019s <code>sendHitTask<\/code>. Unfortunately, when building standard Ecommerce hits, or when automatically sampling timing hits, the tag is automatically sent more than once. Thus the reference to the original <code>sendHitTask<\/code> is recursively augmented with each iteration of <code>model.set('sendHitTask');<\/code>, resulting in code being executed erratically.<\/p>\n<p>By having a global variable store the reference to the original <code>sendHitTask<\/code>, this recursive problem is avoided.<\/p>\n<h3 id=\"3-track-offline-users-in-google-analytics\">3. Track offline users in Google Analytics<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/track-users-who-are-offline-in-google-analytics\/\">Track Users Who Are Offline In Google Analytics<\/a>.<\/p>\n<p>This is all <a href=\"https:\/\/www.thyngster.com\/\">David Vallejo<\/a>. His solution tackles the problem of lost internet connectivity and hits that are aborted because of this. It uses <code>customTask<\/code> to check if the user is offline, and if they are, the hits are stored in a batch queue. Once connectivity is restored, the queue is processed, and the hits are finally sent to GA.<\/p>\n<h3 id=\"4-remove-pii-from-ga-payloads\">4. Remove PII from GA payloads<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/remove-pii-google-analytics-hits\/\">#GTMTips: Remove PII From Google Analytics Hits<\/a>.<\/p>\n<p>With GDPR coming soon, covering all your bases with regard to private data is a good idea. Fixing potential PII leaks before they hit Google Analytics servers is a good method as any to make sure you\u2019re complying with Google Analytics\u2019 Terms of Service as well as the increasingly stricter regulations for sending and collecting personal data.<\/p>\n<div style=\"aspect-ratio: 1600 \/ 462;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/02\/redacted-email.jpg\" title=\"Redacted email\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"462\" width=\"1600\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/02\/redacted-email.jpg#ZgotmplZ\" alt=\"Redacted email\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Here, <code>customTask<\/code> takes the hit payload before it is sent to GA, and purges it of all matches against any given regular expressions. These regular expressions can be built to match things like email addresses and social security numbers.<\/p>\n<h3 id=\"5-fix-site-speed-sampling-messing-with-your-custom-metrics\">5. Fix site speed sampling messing with your Custom Metrics<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/prevent-site-speed-sampling-rate-skewing-custom-dimensions-custom-metrics\/\">Prevent Site Speed Sampling Rate From Skewing Custom Dimensions And Custom Metrics<\/a>.<\/p>\n<p>This is a fairly simple trick, but it fixes a potential issue with Custom Metric data being skewed by the automatically collected page timing hits. The issue is that the timing hit copies all parameters from the Page View tag that is being sampled, and thus any Custom Dimensions and Custom Metrics are sent more than once, too.<\/p>\n<p>Here, <code>customTask<\/code> is attached to the Page View tag, where it checks if the hit type is <code>timing<\/code> (due to the automatically generated timing hit), and if it is, it removes all references to Custom Dimensions and Metrics from the request.<\/p>\n<h3 id=\"6-respect-opt-out\">6. Respect opt-out<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/respect-opt-out-from-advertising-and-analytics\/\">#GTMTips: Respect Opt-Out From Advertising And Analytics<\/a>.<\/p>\n<p>A simple trick, again. This time <code>customTask<\/code> checks if the user has specific opt-out settings in the browser, and if they do, it aborts the requests to Google Analytics and DoubleClick. You\u2019ll need to manually create the setting itself, be it a pop-up that stores the opt-out in a browser cookie or something, but once you\u2019ve done it, this solution makes it easy to enact the opt-out programmatically.<\/p>\n<h3 id=\"7-send-details-about-optimize-experiments-to-google-analytics\">7. Send details about Optimize experiments to Google Analytics<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/send-event-custom-dimension-google-optimize-experiment-running\/\">Send Event And Custom Dimension If Google Optimize Experiment Is Running<\/a>.<\/p>\n<p>This trick tackles an issue with how Google Optimize data is being reported in Google Analytics. Basically, the Experiment Name and Experiment ID dimensions are scoped to the user for the duration of the experiment. Thus it\u2019s not possible to get a segment of the actual sessions when the user was actively participating in an experiment page.<\/p>\n<p>The <code>customTask<\/code> checks for certain features of the Page View tag it is attached to, and if these features are found, it updates a Custom Dimension in the hit payload with details about the experiment. You can then segment your GA data with these Custom Dimensions to see sessions where the user was actually active on an experiment page.<\/p>\n<h3 id=\"8-auto-link-domains-with-regular-expressions\">8. Auto-link domains with regular expressions<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/auto-link-domains-with-regex\/\">#GTMTips: Auto Link Domains With Regex<\/a>.<\/p>\n<p>With this trick, <code>customTask<\/code> brings Google Tag Manager to feature parity with analytics.js. Regular, on-page Google Analytics tracking <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/linker#autolink\">lets you use regular expressions<\/a> with the Auto-Link Domains plugin. Google Tag Manager only accepts string values.<\/p>\n<p>Here, <code>customTask<\/code> actually applies the Auto-Link plugin to the tracker object itself, passing the array of regular expressions to the plugin. This way, domains can be automatically linked with cross-domain parameters based on a regular expression match, rather than an exhaustive list of strings.<\/p>\n<h3 id=\"9-send-google-analytics-payloads-to-snowplow\">9. Send Google Analytics payloads to Snowplow<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/automatically-fork-google-analytics-hits-snowplow\/\">#GTMTips: Automatically Duplicate Google Analytics Hits To Snowplow<\/a>.<\/p>\n<p>I\u2019m a huge fan of <a href=\"https:\/\/snowplowanalytics.com\">Snowplow<\/a>, mainly because it\u2019s open-source and tackles many difficult issues having to do with <a href=\"https:\/\/www.simoahava.com\/analytics\/the-schema-conspiracy\/\">sessionization and tracking schemas<\/a>. This trick uses <code>customTask<\/code> to replicate what the \u201cofficial\u201d Snowplow <a href=\"https:\/\/github.com\/snowplow-incubator\/snowplow-google-analytics-plugin\">Google Analytics plugin<\/a> does.<\/p>\n<div style=\"aspect-ratio: 2466 \/ 758;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/02\/snowplow-open-source-img.jpg\" title=\"Snowplow open source\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"758\" width=\"2466\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/02\/snowplow-open-source-img.jpg#ZgotmplZ\" alt=\"Snowplow open source\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Google Tag Manager doesn\u2019t support adding plugins to tags, so using <code>customTask<\/code> to replicate plugin features is as good a solution as any.<\/p>\n<h3 id=\"10-send-google-analytics-payload-length-as-a-custom-dimension\">10. Send Google Analytics payload length as a Custom Dimension<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/send-google-analytics-payload-length-as-custom-dimension\/\">Send Google Analytics Payload Length As Custom Dimension<\/a>.<\/p>\n<p>This tip lets you collect the payload length of each Google Analytics request as a Custom Dimension in Google Analytics.<\/p>\n<p>The maximum length of a Google Analytics payload is <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/protocol\/v1\/reference#using-post\">8192 bytes<\/a>. It\u2019s useful to check if you\u2019re approaching this value with some of your hits, because if the payload length exceeds this, the hit is never sent to Google Analytics.<\/p>\n<p>Be sure to check my tip below on how to automatically reduce the payload length.<\/p>\n<h3 id=\"11-send-hit-type-as-a-custom-dimension\">11. Send Hit Type as a Custom Dimension<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/add-hit-type-custom-dimension\/\">#GTMTips: Add Hit Type As A Custom Dimension<\/a>.<\/p>\n<p>With this trick, you can send the hit type (e.g. <code>pageview<\/code>, <code>event<\/code>, <code>timing<\/code>) as a Custom Dimension with every hit to which this <code>customTask<\/code> is attached.<\/p>\n<p>Very useful for debugging, since you can now build segments where you directly refer to the hit type, which is not available (surprisingly) as a default dimension in Google Analytics.<\/p>\n<h3 id=\"12-automatically-reduce-payload-length\">12. Automatically reduce payload length<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/automatically-reduce-google-analytics-payload-length\/\">Automatically Reduce Google Analytics Payload Length<\/a>.<\/p>\n<p>With this <code>customTask<\/code>, the payload sent to Google Analytics is automatically parsed and, if necessary, reduced to go under the maximum payload length of 8192 bytes.<\/p>\n<p>It\u2019s very typical especially with Enhanced Ecommerce to send very long payloads to Google Analytics. Unfortunately, if these payloads exceed the maximum length, the hits are never sent and key data will thus be missing from your data set.<\/p>\n<p>You can use this trick to recursively parse the payload and drop unnecessary parameters from it, which only serve to waste valuable space under the length cap.<\/p>\n<h3 id=\"13-create-and-update-a-session-cookie\">13. Create and update a session cookie<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/create-and-update-google-analytics-session-timeout-cookie\/\">Create And Update Google Analytics Session Timeout Cookie<\/a>.<\/p>\n<p>This trick creates (or updates) a browser cookie which expires after a timeout you have configured (30 minutes by default).<\/p>\n<p>Each hit that uses this <code>customTask<\/code> will refresh the cookie very time the hit is fired.<\/p>\n<p>Thus, if this cookie exists in the browser, it\u2019s an indication that there might well be a Google Analytics session active for the current user.<\/p>\n<p>You can use the cookie to block event hits from being dispatched to Google Analytics if there is no active session, for example.<\/p>\n<h3 id=\"14-tracking-cross-domain-iframes\">14. Tracking cross-domain iframes<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/tracking-cross-domain-iframes-upgraded-solution\/\">Tracking Cross-Domain Iframes &#8211; Upgraded Solution<\/a>.<\/p>\n<p>Here we\u2019ll update an <a href=\"https:\/\/www.simoahava.com\/analytics\/iframe-cross-domain-tracking-in-google-tag-manager\/\">older solution of mine<\/a> by using <code>customTask<\/code> and a <code>window.setInterval()<\/code> polling script together to great effect.<\/p>\n<p>The idea is that when the hit is built, the <code>customTask<\/code> looks for the given iframe on the page, and if it\u2019s found within a configured timeout, the iframe is reloaded with cross-domain tracking parameters.<\/p>\n<p>This is a more elegant way to approach the problem of cross-domain iframes, because it skips past the race condition of running the script before the iframe has been loaded on the page, and it also uses the correct tracker object instead of just the first tracker on the page.<\/p>\n<h3 id=\"15-prevent-duplicate-transactions-from-being-sent\">15. Prevent duplicate transactions from being sent<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/prevent-google-analytics-duplicate-transactions-with-customtask\/\">Prevent Duplicate Transactions In Google Analytics With customTask<\/a>.<\/p>\n<p>Again an update to an <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/prevent-repeat-transactions\/\">old trick<\/a>.<\/p>\n<p>In this solution, <code>customTask<\/code> stores all sent <strong>TransactionIDs<\/strong> in the browser. Once a transaction hit is queued for dispatching to GA, the <code>customTask<\/code> checks if the hit\u2019s Transaction ID is found in this list of IDs that have already been sent. If a match is made, the hit is blocked, thus preventing duplicated data from being sent to GA.<\/p>\n<p>If no match is made, the hit is sent normally, and the Transaction ID is written into the list of sent IDs, so that any future attempt to send a transaction with this ID will be blocked.<\/p>\n<p>Contrary to the older solution, this upgraded method will block Enhanced Ecommerce as well. For Standard Ecommerce, you can (and should) still use the <code>customTask<\/code>, but you\u2019ll still need to use triggers and exceptions. This is all detailed behind the link above.<\/p>\n<h3 id=\"16-obfuscate-and-duplicate-google-analytics-data\">16. Obfuscate and duplicate Google Analytics data<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/obfuscate-and-duplicate-google-analytics-data\/\">Obfuscate And Duplicate Google Analytics Data<\/a>.<\/p>\n<p>This is a rather complex little script which duplicates all the Google Analytics data to which the <code>customTask<\/code> is added to, and dispatches it to the Tracking ID you provide in the configuration.<\/p>\n<p>The catch is that in addition to duplicating it, the data is also <strong>obfuscated<\/strong>. All the strings are converted to words in a finite set, and this is done predictably (so any given string is always converted to the same word). All prices are also modified by a randomized percent value.<\/p>\n<p>The point is that you can use this to create a demo or training GA data set out of any actual and real data set without revealing where the data comes from.<\/p>\n<h3 id=\"17-use-localstorage-for-client-id-persistence-in-google-analytics\">17. Use localStorage for Client ID persistence in Google Analytics<\/h3>\n<p>Link to article: <a href=\"https:\/\/www.simoahava.com\/analytics\/use-localstorage-client-id-persistence-google-analytics\/\">#GTMTips: Use localStorage For Client ID Persistence In Google Analytics<\/a>.<\/p>\n<p>Here, I tackle the latest attack on cookie storage by Apple: <a href=\"https:\/\/webkit.org\/blog\/8613\/intelligent-tracking-prevention-2-1\/\">Intelligent Tracking Prevention 2.1<\/a>.<\/p>\n<p>By using <code>localStorage<\/code> to save the Client ID, you can circumvent the policy of limiting cookies set with <code>document.cookie<\/code> to a maximum expiration of 7 days.<\/p>\n<p>It\u2019s not perfect, and it\u2019s definitely more a <strong>tech demo<\/strong> rather than a fully functional solution to solve your enterprise web analytics woes, but the functionality should be sound. There are some hiccups with regard to cross-domain tracking, so remember to revisit the article if you find that something is broken &#8211; I\u2019m going to try to keep it up-to-date if Google decides to update the cross-domain linker parameter format, for example.<\/p>\n<h2 id=\"putting-it-all-together-literally\">Putting it all together (literally)<\/h2>\n<blockquote>\n<p><strong>NOTE!<\/strong> I\u2019ve built a <a href=\"https:\/\/www.simoahava.com\/tools\/customtask-builder\/\">tool<\/a> which you can use to compile the necessary JavaScript automatically. You\u2019ll still want to read through this chapter, though, as it explains why building the script can be a chore.<\/p>\n<\/blockquote>\n<p>If you like <code>customTask<\/code> as much as I do, chances are you\u2019ll want to use more than one trick listed above (and elsewhere) in your tags. There\u2019s a catch though. You need to respect the basic features of JavaScript, mainly:<\/p>\n<ul>\n<li>\n<p>You can only <code>set<\/code> a single field once per tag, so you can only set one <code>customTask<\/code> field per tag.<\/p>\n<\/li>\n<li>\n<p>You can only <code>set<\/code> a single model parameter once per tag, so you can only set one <code>sendHitTask<\/code> attribute per tag, for example.<\/p>\n<\/li>\n<\/ul>\n<p>So, let\u2019s say you want to do both tricks (2) (<a href=\"#2-duplicate-google-analytics-tags-to-more-than-one-property\">Send GA hit to more than one property<\/a>) and (4) (<a href=\"#4-remove-pii-from-ga-payloads\">Remove PII from GA hits<\/a>). You might be tempted to try 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\">return<\/span> <span style=\"color:#00a\">function<\/span>(model) {\n  \n    <span style=\"color:#aaa;font-style:italic\">\/\/ Specify the PII regular expressions\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> piiRegEx = [{\n      name: <span style=\"color:#a50\">'EMAIL'<\/span>,\n      regex: <span style=\"color:#099\">\/.{4}@.{4}\/g<\/span>\n    }];\n    \n    <span style=\"color:#00a\">var<\/span> globalSendTaskName = <span style=\"color:#a50\">'_'<\/span> + model.get(<span style=\"color:#a50\">'trackingId'<\/span>) + <span style=\"color:#a50\">'_originalSendTask'<\/span>;\n    \n    <span style=\"color:#00a\">var<\/span> originalSendTask = <span style=\"color:#0aa\">window<\/span>[globalSendTaskName] = <span style=\"color:#0aa\">window<\/span>[globalSendTaskName] || model.get(<span style=\"color:#a50\">'sendHitTask'<\/span>);\n    \n    <span style=\"color:#aaa;font-style:italic\">\/\/ Clear the payload from PII:\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    model.set(<span style=\"color:#a50\">'sendHitTask'<\/span>, <span style=\"color:#00a\">function<\/span>(sendModel) {\n      \n      ...\n      \n    });\n    \n    <span style=\"color:#aaa;font-style:italic\">\/\/ Duplicate the hit to another tracking ID:\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    model.set(<span style=\"color:#a50\">'sendHitTask'<\/span>, <span style=\"color:#00a\">function<\/span>(sendModel) {\n      \n      ...\n      \n    });\n    \n  };\n}\n<\/code><\/pre>\n<\/div>\n<p>Unfortunately, this would not work. You are setting the <code>sendHitTask<\/code> field twice, meaning the second one is the only one that counts (since it overwrites the first <code>set<\/code>).<\/p>\n<p>Instead, you need to apply some JavaScript chops and combine both of these solutions in the same <code>sendHitTask<\/code>. It\u2019s not exactly trivial, and there\u2019s no textbook method for doing it. You\u2019ll need to figure out the order in which the code should be processed.<\/p>\n<p>In this example, we want the PII purge to happen before any hits are sent or duplicated. So the final code would look 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\">return<\/span> <span style=\"color:#00a\">function<\/span>(model) {\n  \n    <span style=\"color:#aaa;font-style:italic\">\/\/ Specify the PII regular expressions\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> piiRegEx = [{\n      name: <span style=\"color:#a50\">'EMAIL'<\/span>,\n      regex: <span style=\"color:#099\">\/.{4}@.{4}\/g<\/span>\n    }];\n  \n    <span style=\"color:#aaa;font-style:italic\">\/\/ Specify the GA tracking ID of the property to which you want to duplicate the hits\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> newTrackingId = <span style=\"color:#a50\">'UA-12345-2'<\/span>;\n  \n    <span style=\"color:#00a\">var<\/span> globalSendTaskName = <span style=\"color:#a50\">'_'<\/span> + model.get(<span style=\"color:#a50\">'trackingId'<\/span>) + <span style=\"color:#a50\">'_originalSendTask'<\/span>;\n  \n    <span style=\"color:#00a\">var<\/span> originalSendTask = <span style=\"color:#0aa\">window<\/span>[globalSendTaskName] = <span style=\"color:#0aa\">window<\/span>[globalSendTaskName] || model.get(<span style=\"color:#a50\">'sendHitTask'<\/span>);\n  \n    <span style=\"color:#00a\">var<\/span> i, hitPayload, parts, val, oldTrackingId;\n  \n    model.set(<span style=\"color:#a50\">'sendHitTask'<\/span>, <span style=\"color:#00a\">function<\/span>(sendModel) {\n  \n      <span style=\"color:#aaa;font-style:italic\">\/\/ Clear the payload of PII:\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>      hitPayload = sendModel.get(<span style=\"color:#a50\">'hitPayload'<\/span>).split(<span style=\"color:#a50\">'&amp;'<\/span>);\n    \n      <span style=\"color:#00a\">for<\/span> (i = <span style=\"color:#099\">0<\/span>; i '=');\n      \n        <span style=\"color:#aaa;font-style:italic\">\/\/ Double-decode, to account for web server encode + analytics.js encode\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        val = <span style=\"color:#0aa\">decodeURIComponent<\/span>(<span style=\"color:#0aa\">decodeURIComponent<\/span>(parts[<span style=\"color:#099\">1<\/span>]));\n      \n        piiRegEx.forEach(<span style=\"color:#00a\">function<\/span>(pii) {\n          val = val.replace(pii.regex, <span style=\"color:#a50\">'[REDACTED '<\/span> + pii.name + <span style=\"color:#a50\">']'<\/span>);\n        });\n      \n        parts[<span style=\"color:#099\">1<\/span>] = <span style=\"color:#0aa\">encodeURIComponent<\/span>(val);\n        hitPayload[i] = parts.join(<span style=\"color:#a50\">'='<\/span>);\n      }\n    \n      sendModel.set(<span style=\"color:#a50\">'hitPayload'<\/span>, hitPayload.join(<span style=\"color:#a50\">'&amp;'<\/span>), <span style=\"color:#00a\">true<\/span>);\n      originalSendTask(sendModel);\n    \n      <span style=\"color:#aaa;font-style:italic\">\/\/ Rewrite the tracking ID\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>      hitPayload = sendModel.get(<span style=\"color:#a50\">'hitPayload'<\/span>);\n      oldTrackingId = <span style=\"color:#00a\">new<\/span> <span style=\"color:#0aa\">RegExp<\/span>(sendModel.get(<span style=\"color:#a50\">'trackingId'<\/span>), <span style=\"color:#a50\">'gi'<\/span>);\n      sendModel.set(<span style=\"color:#a50\">'hitPayload'<\/span>, hitPayload.replace(oldTrackingId, newTrackingId), <span style=\"color:#00a\">true<\/span>);\n      originalSendTask(sendModel);\n    });\n  };\n}\n<\/code><\/pre>\n<\/div>\n<p>The code is fairly complex, and complexity increases with each distinct trick you want to run. This is an unfortunate consequence of the limitations of JavaScript and the fact that there is only one <code>customTask<\/code> to manipulate.<\/p>\n<p>In the end, it\u2019s really up to your JavaScript skills. You\u2019ll need to be aware of how the browser runs the code line-by-line, and thus you\u2019ll need to make sure that whatever you want to run first is also executed first by the browser. That\u2019s why in the example above I have the PII purge running before the hit duplication. If the PII purge happened AFTER the hit is duplicated, it would be redundant, since it would still allow PII to potentially flow to Google Analytics.<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>As I wrote in the beginning, <code>customTask<\/code> is one of the nicest features to emerge in Google Analytics in a long time. With Google Tag Manager, it\u2019s a real powerhouse of customization.<\/p>\n<p>It\u2019s a good idea to read about the <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/tasks\">Task queue<\/a> in general. Understanding how tasks work will give you great insight into how analytics.js compiles and dispatches hits to Google Analytics. Once you have a good grasp on all the different moving parts of the Tasks queue, you should be able to come up with cool <code>customTask<\/code> solutions of your own, which you can then share in the comments of this article, for example!<\/p>\n<\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>Last updated 4 September 2018 If you have been reading my blog articles over the past year, you might have noticed a disturbing trend. I\u2019ve published 9 articles on customTask since the API was released. It might not sound like much, but I can\u2019t think of a single feature in Google Analytics or Google Tag [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":109976,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[27402,3767,47087,2059,27401],"dealstore":[],"offerexpiration":[],"class_list":["post-109975","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-ahavas","tag-blog","tag-customtask","tag-guide","tag-simo"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>customTask - The Guide | 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=109975\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"customTask - The Guide | Simo Ahava&#039;s blog - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"Last updated 4 September 2018 If you have been reading my blog articles over the past year, you might have noticed a disturbing trend. I\u2019ve published 9 articles on customTask since the API was released. It might not sound like much, but I can\u2019t think of a single feature in Google Analytics or Google Tag [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=109975\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-25T22:37:34+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/customtask-the-guide.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"874\" \/>\n\t<meta property=\"og:image:height\" content=\"485\" \/>\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=\"20 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=109975#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=109975\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"customTask &#8211; The Guide | Simo Ahava&#8217;s blog\",\"datePublished\":\"2025-02-25T22:37:34+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=109975\"},\"wordCount\":3629,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=109975#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/customtask-the-guide.jpg\",\"keywords\":[\"Ahavas\",\"Blog\",\"customTask\",\"Guide\",\"Simo\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=109975#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=109975\",\"url\":\"https:\/\/fivemor.com\/?p=109975\",\"name\":\"customTask - The Guide | Simo Ahava's blog - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=109975#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=109975#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/customtask-the-guide.jpg\",\"datePublished\":\"2025-02-25T22:37:34+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=109975#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=109975\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=109975#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/customtask-the-guide.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/customtask-the-guide.jpg\",\"width\":874,\"height\":485},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=109975#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"customTask &#8211; The Guide | 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":"customTask - The Guide | 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=109975","og_locale":"en_US","og_type":"article","og_title":"customTask - The Guide | Simo Ahava's blog - Som2ny Network","og_description":"Last updated 4 September 2018 If you have been reading my blog articles over the past year, you might have noticed a disturbing trend. I\u2019ve published 9 articles on customTask since the API was released. It might not sound like much, but I can\u2019t think of a single feature in Google Analytics or Google Tag [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=109975","og_site_name":"Som2ny Network","article_published_time":"2025-02-25T22:37:34+00:00","og_image":[{"width":874,"height":485,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/customtask-the-guide.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"20 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=109975#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=109975"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"customTask &#8211; The Guide | Simo Ahava&#8217;s blog","datePublished":"2025-02-25T22:37:34+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=109975"},"wordCount":3629,"commentCount":0,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=109975#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/customtask-the-guide.jpg","keywords":["Ahavas","Blog","customTask","Guide","Simo"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=109975#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=109975","url":"https:\/\/fivemor.com\/?p=109975","name":"customTask - The Guide | Simo Ahava's blog - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=109975#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=109975#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/customtask-the-guide.jpg","datePublished":"2025-02-25T22:37:34+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=109975#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=109975"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=109975#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/customtask-the-guide.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/customtask-the-guide.jpg","width":874,"height":485},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=109975#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"customTask &#8211; The Guide | 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\/109975","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=109975"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/109975\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/109976"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=109975"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=109975"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=109975"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=109975"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=109975"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}