{"id":83512,"date":"2025-02-12T07:31:00","date_gmt":"2025-02-12T07:31:00","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/gtmtips-build-a-custom-universal-analytics-client-for-server-side-tagging\/"},"modified":"2025-02-12T07:31:00","modified_gmt":"2025-02-12T07:31:00","slug":"gtmtips-build-a-custom-universal-analytics-client-for-server-side-tagging","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=83512","title":{"rendered":"#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p>You can utilize <a href=\"https:\/\/www.simoahava.com\/analytics\/server-side-tagging-google-tag-manager\/\"><em>Server-side tagging<\/em><\/a> in <a href=\"https:\/\/tagmanager.google.com\/\">Google Tag Manager<\/a> to build your own custom Universal Analytics proxy.<\/p>\n<p>This proxy comes in the shape of a new <strong>Client<\/strong> <a href=\"https:\/\/www.simoahava.com\/analytics\/custom-templates-guide-for-google-tag-manager\/\">custom template<\/a>, which takes the incoming <code>\/collect<\/code> requests and sends them to Google Analytics. While doing so, it also returns the <code>_ga<\/code> cookie in a <code>Set-Cookie<\/code> header, thus preventing Safari\u2019s <a href=\"https:\/\/www.cookiestatus.com\/safari\/\">Intelligent Tracking Prevention<\/a> from capping its expiration to just 7 days.<\/p>\n<blockquote>\n<p>You might also be interested in reading what <a href=\"https:\/\/www.simoahava.com\/analytics\/fpid-cookie-google-analytics-server-side-tagging\/\">Google\u2019s own solution<\/a> is for migrating from JavaScript cookies to those set in HTTP headers.<\/p>\n<\/blockquote>\n<p>I\u2019ve also created a video that is <em>similar<\/em> though a bit more advanced than this written tutorial.<\/p>\n<blockquote>\n<p><strong>NOTE!<\/strong> The video has one important omission. When creating the <strong>Client<\/strong> template, make sure to update the \u201cSends HTTP Requests\u201d permission to include \u201cAllow Google Domains\u201d. Otherwise the proxying of analytics.js doesn\u2019t work.<\/p>\n<\/blockquote>\n<p>\n  <iframe src=\"https:\/\/www.youtube-nocookie.com\/embed\/_c4JEfSkP6U?enablejsapi=1\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;\" allowfullscreen=\"\" title=\"YouTube Video\"><\/iframe>\n<\/p>\n<p>If the video doesn\u2019t work, you can watch it <a href=\"https:\/\/youtu.be\/_c4JEfSkP6U\">here<\/a>.<\/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=\"tip-117-build-a-universal-analytics-client\">Tip 117: Build a Universal Analytics Client<\/h2>\n<div style=\"aspect-ratio: 960 \/ 540;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/07\/custom-universal-analytics-client.jpg\" title=\"Custom Universal Analytics Client\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"540\" width=\"960\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/07\/custom-universal-analytics-client.jpg#ZgotmplZ\" alt=\"Custom Universal Analytics Client\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>To get things working, you need a couple of things:<\/p>\n<ul>\n<li>A fully functional <a href=\"https:\/\/www.simoahava.com\/analytics\/server-side-tagging-google-tag-manager\/\">Server-side tagging<\/a> setup.<\/li>\n<li>A Client running in the Server container (we\u2019ll build this now).<\/li>\n<li>A Universal Analytics tag in the Server container (I\u2019ll instruct this as well).<\/li>\n<li>Modifications to <em>all<\/em> the Universal Analytics tags firing in the web container (yes, I\u2019ll help with this as well).<\/li>\n<\/ul>\n<p>You will use <em>regular Universal Analytics tags<\/em> in the web container, but you\u2019ll set their <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/send-google-analytics-requests-custom-endpoint\/\">Transport URL<\/a> field to point to your Server endpoint. These tags will only be used for sending the data to the Server container rather than directly to Google Analytics.<\/p>\n<div style=\"aspect-ratio: 1298 \/ 884;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/07\/transport-url-example.jpg\" title=\"Transport URL example\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"884\" width=\"1298\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/07\/transport-url-example.jpg#ZgotmplZ\" alt=\"Transport URL example\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Next, <strong>all<\/strong> the Universal Analytics tags in the web container will need the following modification in their Fields to Set (using a <a href=\"https:\/\/www.simoahava.com\/analytics\/google-analytics-settings-variable-in-gtm\/\">Google Analytics Settings variable<\/a> is recommended).<\/p>\n<div style=\"aspect-ratio: 1754 \/ 428;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/07\/cookieupdate-field-false.jpg\" title=\"cookieUpdate field\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"428\" width=\"1754\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/07\/cookieupdate-field-false.jpg#ZgotmplZ\" alt=\"cookieUpdate field\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>This field prevents the Universal Analytics JavaScript from refreshing the <code>_ga<\/code> cookie. You want to do this because the whole purpose of the <code>Set-Cookie<\/code> header we\u2019ll configure in the Server container is to prevent the web browser from setting the <code>_ga<\/code> cookie with JavaScript. All JavaScript-set cookies are prevented by Safari from having a longer expiration than 7 days.<\/p>\n<blockquote>\n<p>Remember, this field must be set in <strong>all<\/strong> Universal Analytics tags. Even a single tag without this will rewrite the cookie when it fires and thus will negate any benefit you derived from the custom Client.<\/p>\n<\/blockquote>\n<p>Finally, the proxy itself.<\/p>\n<h3 id=\"build-the-client\">Build the Client<\/h3>\n<p>To build the proxy, you need a new <strong>Client template<\/strong>, built in the Server container. In the Server container UI, browse to <strong>Templates<\/strong> and click to create a new <strong>Client<\/strong> template.<\/p>\n<div style=\"aspect-ratio: 2486 \/ 916;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/07\/client-template-new.jpg\" title=\"New Client Template\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"916\" width=\"2486\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/07\/client-template-new.jpg#ZgotmplZ\" alt=\"New Client Template\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>In the first tab, give the template a name and a brief description. If you want, you can also add an icon image.<\/p>\n<p>For this particular template, you can skip the <strong>Fields<\/strong> tab. We don\u2019t need the Client to support any customization.<\/p>\n<p>In <strong>Code<\/strong>, copy-paste the following:<\/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\">const<\/span> claimRequest = require(<span style=\"color:#a50\">'claimRequest'<\/span>);\n<span style=\"color:#00a\">const<\/span> extractEventsFromMpv1 = require(<span style=\"color:#a50\">'extractEventsFromMpv1'<\/span>);\n<span style=\"color:#00a\">const<\/span> getCookie = require(<span style=\"color:#a50\">'getCookieValues'<\/span>);\n<span style=\"color:#00a\">const<\/span> getRemoteAddress = require(<span style=\"color:#a50\">'getRemoteAddress'<\/span>);\n<span style=\"color:#00a\">const<\/span> getRequestHeader = require(<span style=\"color:#a50\">'getRequestHeader'<\/span>);\n<span style=\"color:#00a\">const<\/span> isRequestMpv1 = require(<span style=\"color:#a50\">'isRequestMpv1'<\/span>);\n<span style=\"color:#00a\">const<\/span> returnResponse = require(<span style=\"color:#a50\">'returnResponse'<\/span>);\n<span style=\"color:#00a\">const<\/span> runContainer = require(<span style=\"color:#a50\">'runContainer'<\/span>);\n<span style=\"color:#00a\">const<\/span> setCookie = require(<span style=\"color:#a50\">'setCookie'<\/span>);\n<span style=\"color:#00a\">const<\/span> setPixelResponse = require(<span style=\"color:#a50\">'setPixelResponse'<\/span>);\n<span style=\"color:#00a\">const<\/span> setResponseHeader = require(<span style=\"color:#a50\">'setResponseHeader'<\/span>);\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ Get User-Agent and IP from incoming request\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">const<\/span> ua = getRequestHeader(<span style=\"color:#a50\">'user-agent'<\/span>);\n<span style=\"color:#00a\">const<\/span> ip = getRemoteAddress();\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ Check if request is Measurement Protocol\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">if<\/span> (isRequestMpv1()) {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Claim the request\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  claimRequest();\n  \n  <span style=\"color:#00a\">const<\/span> events = extractEventsFromMpv1();\n  <span style=\"color:#00a\">const<\/span> max = events.length - <span style=\"color:#099\">1<\/span>;\n  events.forEach((event, i) =&gt; {\n    <span style=\"color:#aaa;font-style:italic\">\/\/ Unless the event had IP and user-agent overrides, manually\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#aaa;font-style:italic\">\/\/ override them with the IP and user-agent from the request\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#aaa;font-style:italic\">\/\/ That way the GA collect call will appear to have originated\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#aaa;font-style:italic\">\/\/ from the user's browser \/ device.\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">if<\/span>(!event.ip_override &amp;&amp; ip) event.ip_override = ip;\n    <span style=\"color:#00a\">if<\/span>(!event.user_agent &amp;&amp; ua) event.user_agent = ua;\n    \n    <span style=\"color:#aaa;font-style:italic\">\/\/ Pass the event to a virtual container\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    runContainer(event, () =&gt; {\n      \n      <span style=\"color:#00a\">if<\/span> (i === max) {\n        \n        <span style=\"color:#aaa;font-style:italic\">\/\/ Rewrite the _ga cookie to avoid Safari expiration.\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#00a\">const<\/span> ga = getCookie(<span style=\"color:#a50\">'_ga'<\/span>);\n        <span style=\"color:#00a\">if<\/span> (ga &amp;&amp; ga.length) {\n          setCookie(<span style=\"color:#a50\">'_ga'<\/span>, ga[<span style=\"color:#099\">0<\/span>], {\n            domain: <span style=\"color:#a50\">'auto'<\/span>,\n            <span style=\"color:#a50\">'max-age'<\/span>: <span style=\"color:#099\">63072000<\/span>,\n            path: <span style=\"color:#a50\">'\/'<\/span>,\n            secure: <span style=\"color:#00a\">true<\/span>,\n            sameSite: <span style=\"color:#a50\">'lax'<\/span>\n          });\n        }\n        setPixelResponse();\n        \n        <span style=\"color:#aaa;font-style:italic\">\/\/ Make sure no CORS errors pop up with the response\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#00a\">const<\/span> origin = getRequestHeader(<span style=\"color:#a50\">'Origin'<\/span>);\n\t\t<span style=\"color:#00a\">if<\/span> (origin) {\n          setResponseHeader(<span style=\"color:#a50\">'Access-Control-Allow-Origin'<\/span>, origin);\n          setResponseHeader(<span style=\"color:#a50\">'Access-Control-Allow-Credentials'<\/span>, <span style=\"color:#a50\">'true'<\/span>);\n        }\n        returnResponse();\n      }\n    });\n  });\n}\n<\/code><\/pre>\n<\/div>\n<p>Once the APIs have loaded, the Client pulls in the source\u2019s IP address and User-Agent string with 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\">const<\/span> ua = getRequestHeader(<span style=\"color:#a50\">'user-agent'<\/span>);\n<span style=\"color:#00a\">const<\/span> ip = getRemoteAddress();\n<\/code><\/pre>\n<\/div>\n<p>Next, the <a href=\"https:\/\/developers.google.com\/tag-manager\/serverside\/api#isrequestmpv1\"><code>isRequestMpv1<\/code><\/a> API is utilized to automatically check if the incoming HTTP request is a Measurement Protocol (v1, i.e. Universal Analytics) request. If it is, then the Client <strong>claims<\/strong> the request, and thus prevents other Clients from processing it.<\/p>\n<p>The rest of the Client is concerned with iterating through all the events in the request, parsing them automatically into the required event schema (using the <code>extractEventsFromMpv1<\/code> API), and running the container with all the events in the batch.<\/p>\n<blockquote>\n<p>Typically there will be just one event in each batch.<\/p>\n<\/blockquote>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">if<\/span> (!event.ip_override &amp;&amp; ip) event.ip_override = ip;\n<span style=\"color:#00a\">if<\/span> (!event.user_agent &amp;&amp; ua) event.user_agent = ua;\n<\/code><\/pre>\n<\/div>\n<p>The two lines of code above have a very important function. They take the <em>user\u2019s<\/em> IP address and User-Agent string and pass them to the event data object so that the Universal Analytics tag can then add them into the outgoing request to Google. If you didn\u2019t set these, the IP address and User-Agent string would be set to those of the Server container itself, which is not very useful.<\/p>\n<p>Once all the events have been processed by the container, the following code block is run:<\/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\">const<\/span> ga = getCookie(<span style=\"color:#a50\">'_ga'<\/span>);\n<span style=\"color:#00a\">if<\/span> (ga &amp;&amp; ga.length) {\n  setCookie(<span style=\"color:#a50\">'_ga'<\/span>, ga[<span style=\"color:#099\">0<\/span>], {\n    domain: <span style=\"color:#a50\">'auto'<\/span>,\n    <span style=\"color:#a50\">'max-age'<\/span>: <span style=\"color:#099\">63072000<\/span>,\n    path: <span style=\"color:#a50\">'\/'<\/span>,\n    secure: <span style=\"color:#00a\">true<\/span>,\n    sameSite: <span style=\"color:#a50\">'lax'<\/span>\n  });\n}\n<\/code><\/pre>\n<\/div>\n<p>This piece of code checks the incoming HTTP request for a cookie named <code>_ga<\/code>. If it finds one, it rewrites the cookie with a <code>Set-Cookie<\/code> header, thus converting it to an HTTP cookie and helping solve expiration issues with Safari\u2019s ITP.<\/p>\n<p><code>setPixelResponse()<\/code> automatically configures the response back to the source of the request to resemble a 1&#215;1 GIF image with cache-busting headers. Finally, <code>returnResponse()<\/code> is invoked to signal that the Client has completed its work and can respond back to the source of the initial request.<\/p>\n<h3 id=\"set-the-permissions\">Set the permissions<\/h3>\n<p>While in the template editor, visit the <strong>Permissions<\/strong> tab.<\/p>\n<div style=\"aspect-ratio: 2534 \/ 2438;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/07\/permissions-tab.jpg\" title=\"Permissions tab\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"2438\" width=\"2534\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/07\/permissions-tab.jpg#ZgotmplZ\" alt=\"Permissions tab\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Set the permissions as follows:<\/p>\n<ul>\n<li><strong>Accesses response<\/strong>: Any<\/li>\n<li><strong>Reads cookie value(s)<\/strong>: <code>_ga<\/code><\/li>\n<li><strong>Reads request<\/strong>: Any<\/li>\n<li><strong>Sets a cookie<\/strong>: Set as in the image above.<\/li>\n<\/ul>\n<p>Once you\u2019re done with the permissions, you can <strong>Save<\/strong> the template and exit the template editor.<\/p>\n<h3 id=\"create-the-client-trigger-and-tag\">Create the Client, trigger, and tag<\/h3>\n<p>Next, go to <strong>Clients<\/strong> and click the <strong>New<\/strong> button to create a new Client.<\/p>\n<p>Choose your new Client template from the list of available Client types. Next, set the <strong>Priority<\/strong> field to a high value. It\u2019s important that this value is higher than <em>any other<\/em> Universal Analytics Client you might have in the container.<\/p>\n<div style=\"aspect-ratio: 1854 \/ 666;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/07\/new-client-settings.jpg\" title=\"New client settings\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"666\" width=\"1854\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/07\/new-client-settings.jpg#ZgotmplZ\" alt=\"New client settings\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Give the Client a descriptive name (you\u2019ll need this shortly), and then <strong>save<\/strong> this Client.<\/p>\n<p>Then, go to the <strong>Tags<\/strong> UI and click the <strong>New<\/strong> button to create a new Tag.<\/p>\n<p>Choose <strong>Google Analytics: Universal Analytics<\/strong> as the tag type. There\u2019s no need to configure this tag in any way.<\/p>\n<p>Under <strong>Triggers<\/strong>, click the trigger area to select a trigger.<\/p>\n<div style=\"aspect-ratio: 1848 \/ 1244;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/07\/universal-analytics-tag.jpg\" title=\"Universal Analytics\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"1244\" width=\"1848\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/07\/universal-analytics-tag.jpg#ZgotmplZ\" alt=\"Universal Analytics\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>In the overlay, click the blue <strong>+<\/strong> button in the top right corner to create a new trigger.<\/p>\n<div style=\"aspect-ratio: 1848 \/ 742;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/07\/trigger-configuration.jpg\" title=\"Trigger configuration\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"742\" width=\"1848\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/07\/trigger-configuration.jpg#ZgotmplZ\" alt=\"Trigger configuration\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Set the trigger to look like the above. It just needs the single condition. The name you\u2019re checking against is the name you just gave the new Client.<\/p>\n<blockquote>\n<p>If you don\u2019t see <strong>Client Name<\/strong> in the list of available variables, it means you haven\u2019t enabled it as a <strong>Built-in variable<\/strong> yet. Select <strong>Choose Built-in Variable<\/strong> from the drop-down, and pick Client Name from the overlay that appears.<\/p>\n<\/blockquote>\n<p>Once done, save the trigger. Then, save the tag.<\/p>\n<p>You now have the <strong>Client<\/strong>, the <strong>trigger<\/strong>, and the <strong>tag<\/strong>.<\/p>\n<p>You are ready to test the whole setup!<\/p>\n<h3 id=\"preview-and-test\">Preview and test<\/h3>\n<p>Click the <strong>Preview<\/strong> button in the Server container. A new tab should open with the Server container\u2019s <a href=\"https:\/\/www.simoahava.com\/analytics\/server-side-tagging-google-tag-manager\/#preview-and-debug\">Preview panel<\/a>.<\/p>\n<p>In your <strong>web container<\/strong>, similarly click the <strong>Preview<\/strong> button.<\/p>\n<p>Now you should have both your web container and the Server container in Preview mode.<\/p>\n<p>Next, browse to your site and do something to fire one of the Universal Analytics tags you designed for server-side collection. Once the tag fires, check the Preview panel of your Server container. You should see something like this:<\/p>\n<div style=\"aspect-ratio: 1250 \/ 806;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/07\/page-view-in-preview.jpg\" title=\"page_view in preview\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"806\" width=\"1250\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/07\/page-view-in-preview.jpg#ZgotmplZ\" alt=\"page_view in preview\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>If you see it, and there are no errors in the Errors tab, it should work!<\/p>\n<p>You can debug further by selecting the <strong>Universal Analytics<\/strong> tag itself and then clicking the <strong>Outgoing HTTP Requests<\/strong> box. This opens the details for the request to Google Analytics.<\/p>\n<div style=\"aspect-ratio: 1898 \/ 1844;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/08\/outgoing-http-request.jpg\" title=\"Outgoing HTTP request\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"1844\" width=\"1898\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/08\/outgoing-http-request.jpg#ZgotmplZ\" alt=\"Outgoing HTTP request\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Check the Real Time report in your Google Analytics view (you <em>have<\/em> created a separate property for your Server-side tagging hits, right?), and make sure data is flowing in.<\/p>\n<p>Finally, check the cookies in your browser. The <code>_ga<\/code> cookie should have the value of <strong>Secure<\/strong> set to <code>true<\/code> and the value of <strong>SameSite<\/strong> set to <code>Lax<\/code>. If that\u2019s what you see, the cookie rewrite worked!<\/p>\n<div style=\"aspect-ratio: 2528 \/ 590;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/07\/samesite-secure-cookie.jpg\" title=\"SameSite and secure cookie\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"590\" width=\"2528\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/07\/samesite-secure-cookie.jpg#ZgotmplZ\" alt=\"SameSite and secure cookie\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<h2 id=\"summary\">Summary<\/h2>\n<p>There\u2019s a lot of new stuff here, so I wouldn\u2019t be surprised if this is difficult to set up. However, if you follow this guide diligently, and make sure there are no rogue tags firing without <code>cookieUpdate<\/code>, the Client should do its job nicely.<\/p>\n<p>If you run into issues, let me know in the comments and we can take a look together.<\/p>\n<p>Server-side tagging is the new paradigm for Google\u2019s tagging solutions. I can see a lot of amazing things you can do with it in the future, but right now you can also utilize it for improving the quality of your data incrementally with solutions such as this one.<\/p>\n<\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>You can utilize Server-side tagging in Google Tag Manager to build your own custom Universal Analytics proxy. This proxy comes in the shape of a new Client custom template, which takes the incoming \/collect requests and sends them to Google Analytics. While doing so, it also returns the _ga cookie in a Set-Cookie header, thus [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":83513,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[12765,5293,12982,834,14492,18475,29117,1260],"dealstore":[],"offerexpiration":[],"class_list":["post-83512","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-analytics","tag-build","tag-client","tag-custom","tag-gtmtips","tag-serverside","tag-tagging","tag-universal"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging - 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=83512\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"You can utilize Server-side tagging in Google Tag Manager to build your own custom Universal Analytics proxy. This proxy comes in the shape of a new Client custom template, which takes the incoming \/collect requests and sends them to Google Analytics. While doing so, it also returns the _ga cookie in a Set-Cookie header, thus [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=83512\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-12T07:31:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-universal-analytics-client.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"960\" \/>\n\t<meta property=\"og:image:height\" content=\"540\" \/>\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=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=83512#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=83512\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging\",\"datePublished\":\"2025-02-12T07:31:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=83512\"},\"wordCount\":1382,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=83512#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-universal-analytics-client.jpg\",\"keywords\":[\"Analytics\",\"Build\",\"client\",\"Custom\",\"GTMTips\",\"Serverside\",\"Tagging\",\"Universal\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=83512#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=83512\",\"url\":\"https:\/\/fivemor.com\/?p=83512\",\"name\":\"#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=83512#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=83512#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-universal-analytics-client.jpg\",\"datePublished\":\"2025-02-12T07:31:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=83512#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=83512\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=83512#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-universal-analytics-client.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-universal-analytics-client.jpg\",\"width\":960,\"height\":540},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=83512#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging\"}]},{\"@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":"#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging - 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=83512","og_locale":"en_US","og_type":"article","og_title":"#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging - Som2ny Network","og_description":"You can utilize Server-side tagging in Google Tag Manager to build your own custom Universal Analytics proxy. This proxy comes in the shape of a new Client custom template, which takes the incoming \/collect requests and sends them to Google Analytics. While doing so, it also returns the _ga cookie in a Set-Cookie header, thus [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=83512","og_site_name":"Som2ny Network","article_published_time":"2025-02-12T07:31:00+00:00","og_image":[{"width":960,"height":540,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-universal-analytics-client.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=83512#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=83512"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging","datePublished":"2025-02-12T07:31:00+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=83512"},"wordCount":1382,"commentCount":0,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=83512#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-universal-analytics-client.jpg","keywords":["Analytics","Build","client","Custom","GTMTips","Serverside","Tagging","Universal"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=83512#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=83512","url":"https:\/\/fivemor.com\/?p=83512","name":"#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=83512#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=83512#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-universal-analytics-client.jpg","datePublished":"2025-02-12T07:31:00+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=83512#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=83512"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=83512#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-universal-analytics-client.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-universal-analytics-client.jpg","width":960,"height":540},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=83512#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"#GTMTips: Build A Custom Universal Analytics Client For Server-side Tagging"}]},{"@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\/83512","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=83512"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/83512\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/83513"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=83512"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=83512"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=83512"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=83512"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=83512"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}