{"id":124426,"date":"2025-03-10T15:29:44","date_gmt":"2025-03-10T15:29:44","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/google-analytics-client-id-in-amp-pages\/"},"modified":"2025-03-10T15:29:44","modified_gmt":"2025-03-10T15:29:44","slug":"google-analytics-client-id-in-amp-pages","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=124426","title":{"rendered":"Google Analytics Client ID In AMP Pages"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p>This article is a collaboration between Simo and <a href=\"https:\/\/www.bounteous.com\/insights\/author\/danwilkerson\/\">Dan Wilkerson<\/a>. Dan\u2019s one of the smartest analytics developers out there, and he\u2019s already contributed a great <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/using-document-write-safely-gtm-tags\/\">#GTMTips guest post<\/a>. It\u2019s great to have him back here sharing his insight on working with <a href=\"https:\/\/www.ampproject.org\/\">Accelerated Mobile Pages<\/a> (AMP).<\/p>\n<p>So, we\u2019re back on AMP! Simo wrote a long, sprawling <a href=\"https:\/\/www.simoahava.com\/analytics\/accelerated-mobile-pages-via-google-tag-manager\/\">AMP for Google Tag Manager guide<\/a> a while ago, and Dan has also contributed to the space with his guide for <a href=\"https:\/\/www.bounteous.com\/insights\/2015\/12\/08\/google-analytics-using-amp\/\">AMP and Google Analytics<\/a>. Both of these guides touched upon a subject that might be one of the reasons to stay away from AMP for now: Client ID matching across AMP, your regular website, and any caches or CDNs that serve the AMP version.<\/p>\n<div style=\"aspect-ratio: 2030 \/ 1074;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/11\/amp_cookies.jpg\" title=\"AMP cookies\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"1074\" width=\"2030\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/11\/amp_cookies.jpg#ZgotmplZ\" alt=\"AMP cookies\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Not only does AMP have its own, unique syntax for the Client ID, it also stores it in different ways. For example, in the <a href=\"https:\/\/developers.google.com\/amp\/cache\/\">AMP Cache<\/a> (and thus via Google search, too), it\u2019s stored in <code>localStorage<\/code>. If someone visits your site directly and accesses AMP pages, the Client ID is stored in the <code>AMP_ECID_GOOGLE<\/code> cookie. And then if someone visits a regular page on your site, the Client ID can be found in the <code>_ga<\/code> cookie.<\/p>\n<p>In this article, Dan and Simo tackle this issue by showing how to serve the Client ID <em>consistently<\/em> from the <code>_ga<\/code> cookie written on your website\u2019s actual domain. This way, AMP pages will use the same Client ID that regular Google Analytics uses, and you will be able to identify customer journeys that may pass through both your regular site as well as your AMP content.<\/p>\n<p>The examples are provided in NodeJS and PHP (WordPress), but the methodology is universal and quite simple to do with any web server software.<\/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=\"overview\">Overview<\/h2>\n<p>To recap, <a href=\"https:\/\/analytics.google.com\/\">Google Analytics<\/a> stores a unique identifier for every user who visits your site within a first-party <a href=\"http:\/\/www.allaboutcookies.org\/cookies\/\">cookie<\/a>. This value, in GA parlance, is called the <strong>Client ID<\/strong>, and the name of the cookie is <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/analyticsjs\/cookies-user-id\"><code>_ga<\/code><\/a>. Here\u2019s what the entire cookie string looks like, with the actual Client ID bolded.<\/p>\n<p>GA1.2.<strong>1789536866.1471440764<\/strong><\/p>\n<p>The <strong>GA1<\/strong> value denotes this is version 1 of the <code>_ga<\/code> cookie. The <strong>2<\/strong> denotes the number of dot-separated components in the URL the cookie is stored at. For example, if GA were instructed to store the cookie at <strong>shop.example.com<\/strong>, the number would be 3, instead.<\/p>\n<p>Because AMP pages can be cached and served on many different domains, users who might have had a single Client ID could wind up being split into several users instead.<\/p>\n<div style=\"aspect-ratio: 1886 \/ 822;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2016\/11\/amp-client-ids.jpg\" title=\"AMP Client IDs\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"822\" width=\"1886\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2016\/11\/amp-client-ids.jpg#ZgotmplZ\" alt=\"AMP Client IDs\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>This appears to be at least part of the reason behind why Google Analytics officially recommends <a href=\"https:\/\/analytics.googleblog.com\/2016\/01\/announcing-ga-support-for-accelerated.html\">using a separate GA Property for AMP data<\/a>.<\/p>\n<p>However, there\u2019s a way to use <em>only<\/em> the <code>_ga<\/code> cookie for all sources that serve your web content. To do this, we\u2019ll need to customize our <code>amp-analytics<\/code> component.<\/p>\n<h4 id=\"custom-amp-configuration\">Custom AMP configuration<\/h4>\n<p><code>amp-analytics<\/code> is the component that AMP uses for tracking user interactions. If you\u2019d like to learn more about all the features it supports, check out <a href=\"https:\/\/www.simoahava.com\/analytics\/accelerated-mobile-pages-via-google-tag-manager\/\">the AMP for GTM guide in this blog<\/a>; it should have all the information you need.<\/p>\n<p>For our purposes, let\u2019s focus on the <code>config<\/code> attribute. It\u2019s an optional attribute that we can use to tell AMP: <em>\u201cHey, we\u2019ve got some additional configurations that we need to you fetch from this location\u201d<\/em>. This attribute should be set to a URL where additional analytics configurations should be retrieved from. In other words, you need to specify an HTTP request endpoint which returns a valid, <a href=\"https:\/\/www.ampproject.org\/docs\/reference\/components\/amp-analytics\">AMP-compliant JSON<\/a> configuration file.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-html\" data-lang=\"html\">amp-analytics <span style=\"color:#1e90ff\">config<\/span>=<span style=\"color:#a50\">\"\/\/example.com\/analytics.config.json\"<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">amp-analytics<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>Once the browser has loaded the AMP page, and the page is visible in the browser window, AMP will fetch this external configuration file and use it to supplement any configurations that might already be established on the page. Unlike other resources in your content, your <code>amp-analytics<\/code> config will always point to your server and the result isn\u2019t automatically cached. When the request to your server comes in, it will include all of the cookies set on the user\u2019s browser on your domain.<\/p>\n<p><strong>NOTE!<\/strong> If, and when, your content is served through the Google AMP Cache, any external configuration <strong>must be downloaded from an HTTPS source<\/strong>. Thus if your web server is behind HTTP, you\u2019ll need to either only serve your custom configuration when visitors are on your domain OR use just the default configuration template instead. Or, you know, switch to HTTPS as soon as possible.<\/p>\n<h4 id=\"grabbing-the-_ga-cookie\">Grabbing the <code>_ga<\/code> cookie<\/h4>\n<p>When the request for the custom AMP config is received by your web server, you can check the cookies in the HTTP request to see if a <code>_ga<\/code> cookie is already set for the user on the website domain. This would be the case if the user has visited your content before (and hasn\u2019t flushed cookies). If the cookie is found, you can use a specific HTTP header (see below) in the response to pass this cookie to the domain where the request originated from, e.g. Google\u2019s AMP cache.<\/p>\n<p>If the cookie is <em>not<\/em> found, you can generate a new <code>_ga<\/code> cookie, following the same pattern <strong>analytics.js<\/strong> uses &#8211; a random unsigned 32-bit integer coupled with a timestamp rounded to the nearest second, like this:<\/p>\n<p><strong>1789536866.1471440764<\/strong><\/p>\n<p>You can then leverage the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Set-Cookie\"><code>Set-Cookie<\/code><\/a> header in the HTTP Response, and instruct the browser to store the new Client ID in a <code>_ga<\/code> cookie, making sure to set the domain, path, and expiration date to match the domain the request originated from (e.g. <code>cdn.ampproject.org<\/code>), just like analytics.js does. You\u2019ll need to add the same <strong>GA1.X.<\/strong> prefix that GA uses, too. Furthermore, you\u2019ll need to do this on <em>every single<\/em> request, so that the lifetime of the <code>_ga<\/code> cookie continues to be extended on each page load. The <code>Set-Cookie<\/code> should end up looking something like this:<\/p>\n<p><code>Set-Cookie:<\/code> _ga=GA1.1.18347199128.1478727498; Domain=example.com; Path=\/; Expires=Sat, 10 Nov 2018 21:06:48 GMT;<\/p>\n<p>Finally, you can return the Client ID in the JSON response as a custom AMP variable for use with our AMP requests:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-json\" data-lang=\"json\">{\n  <span style=\"color:#1e90ff;font-weight:bold\">\"vars\"<\/span>: {\n    <span style=\"color:#1e90ff;font-weight:bold\">\"clientId\"<\/span>: <span style=\"color:#a50\">\"18347199128.1478727498\"<\/span>\n  }\n}<\/code><\/pre>\n<\/div>\n<h4 id=\"checklist-for-setting-up-the-request-handler\">Checklist for setting up the request handler<\/h4>\n<p>Of course, it\u2019s not quite that simple. In addition to transposing our Client ID and setting it as a cookie, we need to ensure that we\u2019ve dotted a few i\u2019s. Here\u2019s a handy checklist of the configuration steps that need to be taken to ensure everything works in the wild.<\/p>\n<ul>\n<li>\n<p>In the site HTML:<\/p>\n<ul>\n<li>\n<p>Add the <code>amp-analytics<\/code> script tag and <code>amp-analytics<\/code> component to your AMP templates.<\/p>\n<\/li>\n<li>\n<p>Configure component JSON for desired triggers and requests, using <code>${clientId}<\/code> for the <strong>&amp;cid;<\/strong> parameter. Alternatively, you can use the pre-built Google Analytics vendor template by adding <code>type=\"googleanalytics\"<\/code> to the component.<\/p>\n<\/li>\n<li>\n<p>Point <code>config<\/code> attribute to an endpoint or API on your own server.<\/p>\n<\/li>\n<li>\n<p>Set <code>data-credentials=\"include\"<\/code>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>In your web server:<\/p>\n<ul>\n<li>\n<p>In the request handler in your web server, extract the Client ID from the <code>_ga<\/code> cookie or generate a new one.<\/p>\n<\/li>\n<li>\n<p>Add the <code>clientId<\/code> parameter to the <code>vars<\/code> object in the JSON configuration. Set it to the Client ID from the <code>_ga<\/code> cookie.<\/p>\n<\/li>\n<li>\n<p>Add the <code>Set-Cookie<\/code> header with the <code>_ga<\/code> cookie, set to expire in two years.<\/p>\n<\/li>\n<li>\n<p>Set the <code>Access-Control-Allow-Origin<\/code> header to <code>https:\/\/cdn.ampproject.org<\/code>. Note: Wildcards (*) are invalid in this context.<\/p>\n<\/li>\n<li>\n<p>Set the <code>Access-Control-Expose-Headers<\/code> header to <code>AMP-Access-Control-Allow-Source-Origin<\/code>.<\/p>\n<\/li>\n<li>\n<p>Set the <code>Access-Control-Allow-Credentials<\/code> header to <code>true<\/code>.<\/p>\n<\/li>\n<li>\n<p>Set the header <code>AMP-Access-Control-Allow-Source-Origin<\/code> to the source domain of the document (e.g. <code>https:\/\/mysite.com<\/code>).<\/p>\n<\/li>\n<li>\n<p>Return the JSON configuration in the response body.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>For a full example, <a href=\"https:\/\/github.com\/DanWilkerson\/amp-config-example\">check out this repository on GitHub<\/a>. If you\u2019re using the Google Analytics vendor configuration, this is all you need to do. If you\u2019d like to combine this concept with Google Tag Manager, read on!<\/p>\n<h2 id=\"google-tag-manager-proxy-using-nodejs\">Google Tag Manager proxy using NodeJS<\/h2>\n<p>As Simo covered in his <a href=\"https:\/\/www.simoahava.com\/analytics\/accelerated-mobile-pages-via-google-tag-manager\/\">GTM\/AMP guide<\/a>, Google Tag Manager allows us to build Tags and Triggers in a web UI, then compile those down into a JSON configuration in the format AMP expects. If we used the standard GTM implementation, however, the container request is done directly to GTM\u2019s server, which means our custom API wouldn\u2019t be able to serve the proper Client ID. That said, you can still combine both techniques. You\u2019ve just got to roll up your sleeves a little.<\/p>\n<p>Here\u2019s a truncated example, using <a href=\"https:\/\/nodejs.org\/en\/\">Node<\/a> and <a href=\"http:\/\/expressjs.com\/\">Express<\/a>. For the complete code, <a href=\"https:\/\/github.com\/DanWilkerson\/amp-config-example\">visit this GitHub repository<\/a>.<\/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\">app.get(<span style=\"color:#a50\">'\/gtm-analytics.config.json'<\/span>, (req, res) =&gt; {\n\n  <span style=\"color:#00a\">const<\/span> domain = req.headers.host.split(<span style=\"color:#a50\">':'<\/span>)[<span style=\"color:#099\">0<\/span>]\n  <span style=\"color:#00a\">const<\/span> gaCookie = req.cookies._ga || generateGaCookie(domain)\n  <span style=\"color:#00a\">const<\/span> clientId = parseClientIdFromGaCookie(gaCookie)\n  <span style=\"color:#00a\">const<\/span> cookieString = generateCookieString({\n    name: <span style=\"color:#a50\">'_ga'<\/span>,\n    value: gaCookie,\n    domain: domain.replace(<span style=\"color:#a50\">'www.'<\/span>, <span style=\"color:#a50\">''<\/span>),\n    path: <span style=\"color:#a50\">'\/'<\/span>,\n    expires: <span style=\"color:#00a\">new<\/span> <span style=\"color:#0aa\">Date<\/span>(<span style=\"color:#099\">1000<\/span> * <span style=\"color:#099\">60<\/span> * <span style=\"color:#099\">60<\/span> * <span style=\"color:#099\">24<\/span> * <span style=\"color:#099\">365<\/span> * <span style=\"color:#099\">2<\/span> + (+<span style=\"color:#00a\">new<\/span> <span style=\"color:#0aa\">Date<\/span>)).toGMTString()\n  })\n\n  res.setHeader(<span style=\"color:#a50\">'Set-Cookie'<\/span>, cookieString)\n  res.setHeader(<span style=\"color:#a50\">'Access-Control-Allow-Origin'<\/span>, <span style=\"color:#a50\">'https:\/\/cdn.ampproject.org'<\/span>)\n  res.setHeader(<span style=\"color:#a50\">'Access-Control-Expose-Headers'<\/span>, <span style=\"color:#a50\">'AMP-Access-Control-Allow-Source-Origin'<\/span>)\n  res.setHeader(<span style=\"color:#a50\">'Access-Control-Allow-Credentials'<\/span>, <span style=\"color:#a50\">'true'<\/span>)\n  <span style=\"color:#aaa;font-style:italic\">\/\/ AMP-specific header, check your protocol\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  res.setHeader(<span style=\"color:#a50\">'AMP-Access-Control-Allow-Source-Origin'<\/span>, <span style=\"color:#a50\">'https:\/\/'<\/span> + domain)\n\n  request.get({\n    url: <span style=\"color:#a50\">'https:\/\/www.googletagmanager.com\/amp.json'<\/span>,\n    qs: req.query,\n    json: <span style=\"color:#00a\">true<\/span>\n  }, (err, response, data) =&gt; {\n\n    <span style=\"color:#00a\">if<\/span> (err) data = {<span style=\"color:#a50\">\"vars\"<\/span>: {}}  <span style=\"color:#aaa;font-style:italic\">\/\/ Add additional error handling here\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\n    data.vars.clientId = clientId\n\n    data.requests = <span style=\"color:#0aa\">Object<\/span>.keys(data.requests)\n      .reduce((map, key) =&gt; {\n  \n        map[key] = data.requests[key].replace(<span style=\"color:#099\">\/(&amp;cid=)[^&amp;]+\/<\/span>, <span style=\"color:#a50\">'$1${clientId}'<\/span>)\n        <span style=\"color:#00a\">return<\/span> map\n\n      }, {})\n\n    res.json(data)\n\n  })\n\n})\n<\/code><\/pre>\n<\/div>\n<p>Here\u2019s another checklist, this time for combining your custom Client ID workaround with the Google Tag Manager AMP container. I\u2019ve bolded the new steps.<\/p>\n<ul>\n<li>\n<p>In your page HTML:<\/p>\n<ul>\n<li>\n<p>Add the <code>amp-analytics<\/code> script tag and <code>amp-analytics<\/code> component to your AMP templates.<\/p>\n<\/li>\n<li>\n<p>Point <code>config<\/code> attribute to an endpoint or API on your own server.<\/p>\n<\/li>\n<li>\n<p>Set <code>data-credentials<\/code> attribute to <code>include<\/code>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>In your web server:<\/p>\n<ul>\n<li>\n<p>In the request handler in your web server, extract the Client ID from the <code>_ga<\/code> cookie or generate a new one<\/p>\n<\/li>\n<li>\n<p><strong>Request the container JSON from GTM, passing along all query parameters from the original <code>amp-analytics<\/code> request.<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>Replace all instances of \u2018CLIENT_ID(AMP_ECID_GOOGLE)\u2019 in the request with \u2018${clientId}\u2019.<\/strong><\/p>\n<\/li>\n<li>\n<p>Add the <code>clientId<\/code> parameter to the <code>vars<\/code> object in the JSON configuration. Set it to the Client ID from the <code>_ga<\/code> cookie.<\/p>\n<\/li>\n<li>\n<p>Add the <code>Set-Cookie<\/code> header with the <code>_ga<\/code> cookie, set to expire in two years.<\/p>\n<\/li>\n<li>\n<p>Set the <code>Access-Control-Allow-Origin<\/code> header to <code>https:\/\/cdn.ampproject.org<\/code>. Note: Wildcards (*) are invalid in this context.<\/p>\n<\/li>\n<li>\n<p>Set the <code>Access-Control-Expose-Headers<\/code> header to <code>AMP-Access-Control-Allow-Source-Origin<\/code>.<\/p>\n<\/li>\n<li>\n<p>Set the <code>Access-Control-Allow-Credentials<\/code> header to <code>true<\/code>.<\/p>\n<\/li>\n<li>\n<p>Set the header <code>AMP-Access-Control-Allow-Source-Origin<\/code> to the source domain of the document (e.g. <code>https:\/\/mysite.com<\/code>).<\/p>\n<\/li>\n<li>\n<p>Return the JSON configuration in the response body.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>In your site code you\u2019ll need:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-html\" data-lang=\"html\"><span style=\"color:#aaa;font-style:italic\"><!-- Google Tag Manager --><\/span>\namp-analytics <span style=\"color:#1e90ff\">config<\/span>=<span style=\"color:#a50\">\"\/\/www.yourdomain.com\/gtm-analytics.config.json?id=GTM-XXXXX&amp;gtm.url=SOURCE_URL\"<\/span> <span style=\"color:#1e90ff\">data-credentials<\/span>=<span style=\"color:#a50\">\"include\"<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">amp-analytics<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>Congratulations, you have created a web proxy that fetches the Google Tag Manager container from Google\u2019s servers and modifies the JSON to leverage the value stored in the <code>_ga<\/code> cookie.<\/p>\n<h2 id=\"google-tag-manager-proxy-with-wordpress\">Google Tag Manager proxy with WordPress<\/h2>\n<p>This blog is running on WordPress, so Simo wanted to see how trivial it would be to create the endpoint. As it turns out, it\u2019s very simple indeed.<\/p>\n<p>WordPress provides the <a href=\"https:\/\/developer.wordpress.org\/reference\/hooks\/rest_api_init\/\"><code>rest_api_init<\/code><\/a> hook, which lets you create an HTTP request endpoint on your web server:<\/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-php\" data-lang=\"php\">\/\/ REST API for GTM container\nadd_action( 'rest_api_init', function() {\n    register_rest_route( \n        'amp-gtm',\n        '\/amp.json',\n        array(\n            'methods' =&gt; 'GET',\n            'callback' =&gt; 'retrieve_gtm_json',\n        )\n    );\n});<\/code><\/pre>\n<\/div>\n<p>That piece of code in your <strong>functions.php<\/strong> would create a GET request endpoint in your web domain path <code>\/wp-json\/amp-gtm\/amp.json<\/code>. If a GET request to this endpoint is recorded, the callback function named <code>retrieve_gtm_json<\/code> is then invoked:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-php\" data-lang=\"php\">\/\/ Generate random Client ID\nfunction generate_ga_client_id() {\n    return rand(100000000,999999999) . '.' . time();\n}\n\n\/\/ Set cookie to expire in 2 years\nfunction getCookieExpirationDate() {\n    return date('D, j F Y H:i:s', time() + 60*60*24*365*2);\n}\n\n\/\/ Callback for the GET request\nfunction retrieve_gtm_json( $data ) {\n    \/* Get the hostname of the request origin, and parse it for the\n     * pure domain name. *\/\n    $domain = explode(':', $data-&gt;get_header('Host'))[0];\n    $domainName = str_replace('www.', '', $domain);\n\n    \/\/ Get the number of parts in the domain name\n    $domainLength = count(explode('.', $domainName));\n\n    \/* Check if the browser already has the _ga cookie.\n     * If not, generate a new cookie. *\/\n    $cid = $_COOKIE['_ga'];\n    if (!isset($cid)) {\n        $cid = \"GA1.{$domainLength}.\" . generate_ga_client_id();\n    }\n\n    \/* Store the actual Client ID (last two numbers) of the\n     * _ga cookie value in the $cidNumber variable *\/\n    $cidNumber = preg_replace('\/^GA.\\.[^.]+\\.\/','',$cid);\n  \n    \/\/ Get all HTTP request parameters\n    $query = $_SERVER['QUERY_STRING'];\n    \n    \/* Fetch the actual GTM container, by passing the valid query parameters from\n     * the original request. *\/\n    $container = file_get_contents(\"https:\/\/www.googletagmanager.com\/amp.json?{$query}\");\n    \n    \/\/ Replace the <span style=\"color:#800;font-weight:bold\">&amp;cid;<\/span> parameter value with ${clientId}\n    $container = preg_replace('\/(<span style=\"color:#f00;background-color:#faa\">&amp;<\/span>cid=)[^<span style=\"color:#f00;background-color:#faa\">&amp;<\/span>]+\/','${1}${clientId}', $container);\n  \n    \/\/ Add the clientId to the \"vars\" object in the container JSON.\n    $container = json_decode($container);\n    $container-&gt;vars-&gt;clientId = $cidNumber;\n    \n    \/\/ Build a new HTTP response from the modified configuration file.\n    $response = new WP_REST_RESPONSE( $container );\n    \n    \/\/ Add the required headers (Set-Cookie, most importantly) to the Request\n    $response-&gt;header( 'Set-Cookie', \"_ga={$cid}; Path=\/; Expires=\" . getcookieExpirationDate() . \" GMT; Domain={$domainName};\");\n    $response-&gt;header( 'Access-Control-Allow-Origin', 'https:\/\/cdn.ampproject.org');\n    \n    \/\/ Remember to check the protocol and change to http if that's where your domain is\n    $response-&gt;header( 'AMP-Access-Control-Allow-Source-Origin', \"https:\/\/{$domain}\");\n    $response-&gt;header( 'Access-Control-Expose-Headers', 'AMP-Access-Control-Allow-Source-Origin');\n    \n    \/\/ Return the HTTP response.\n    return $response;\n}<\/code><\/pre>\n<\/div>\n<p>This is the API script that handles requests for the Google Tag Manager container. The proxy fetches the GTM container, and replaces the default Client ID with the AMP variable <code>${clientId}<\/code>. This, in turn, is added to the configuration JSON with the value retrieved from the <code>_ga<\/code> cookie. If the <code>_ga<\/code> cookie doesn\u2019t exist, a new one is generated.<\/p>\n<p>In your site code, you\u2019ll need:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-html\" data-lang=\"html\"><span style=\"color:#aaa;font-style:italic\"><!-- Google Tag Manager --><\/span>\namp-analytics <span style=\"color:#1e90ff\">config<\/span>=<span style=\"color:#a50\">\"\/\/www.yourdomain.com\/wp-json\/amp-gtm\/amp.json?id=GTM-XXXXX&amp;gtm.url=SOURCE_URL\"<\/span> <span style=\"color:#1e90ff\">data-credentials<\/span>=<span style=\"color:#a50\">\"include\"<\/span>&gt;<span style=\"color:#1e90ff;font-weight:bold\">amp-analytics<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>This request is then passed to your endpoint, and the process described above will take place.<\/p>\n<h2 id=\"google-analytics-setup\">Google Analytics setup<\/h2>\n<p>Not much has to be done in Google Analytics, but you will want to add <strong>ampproject.org<\/strong> into the <strong>Referral Exclusion List<\/strong> of your Google Analytics property settings. Otherwise, if the user follows any link from the cached AMP page to the rest of your site, the click will start a new session with a referral from ampproject.org.<\/p>\n<p>Thanks to Adrian Vender for this tip!<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>This is a fairly technical topic, but we, the authors, found it necessary to point out this potential flaw in how doing analytics in Accelerated Mobile Pages might be detrimental to your overall tracking plan.<\/p>\n<p>The fact that AMP doesn\u2019t automatically leverage the <code>_ga<\/code> cookie if the request is to Google Analytics, for example, is a bit odd. Similarly, Google Tag Manager defaulting to <code>AMP_ECID_GOOGLE<\/code> is weird too, considering how much easier things would be if you could provide a cookie name or an AMP variable for the Client ID in the request.<\/p>\n<p>Because Google\u2019s AMP cache is a different domain from your own, there\u2019s really no way around Client ID stitching that wouldn\u2019t involve the type of third-party cookie scheme as described in this guide. The request must be allowed to process the cookies written on your domain, so that the same <code>_ga<\/code> cookie value can be used on the pages in the external domain.<\/p>\n<p>Luckily the technical solution to this dilemma is not too complicated. The proxy you create in your web server is simple, and should be easy to configure with any web server software. You might want to add some enhancements of your own, such as caching the Google Tag Manager container locally, and we\u2019d love to hear your tips and experiences in the comments below.<\/p>\n<p>We hope this article gets your stAMP of approval, and that you\u2019ve learned an AMPle amount of new things. Sorry for the puns.<\/p>\n<\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>This article is a collaboration between Simo and Dan Wilkerson. Dan\u2019s one of the smartest analytics developers out there, and he\u2019s already contributed a great #GTMTips guest post. It\u2019s great to have him back here sharing his insight on working with Accelerated Mobile Pages (AMP). So, we\u2019re back on AMP! Simo wrote a long, sprawling [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":124427,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[9093,12765,12982,1531,3845],"dealstore":[],"offerexpiration":[],"class_list":["post-124426","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-amp","tag-analytics","tag-client","tag-google","tag-pages"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Google Analytics Client ID In AMP Pages - 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=124426\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Google Analytics Client ID In AMP Pages - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"This article is a collaboration between Simo and Dan Wilkerson. Dan\u2019s one of the smartest analytics developers out there, and he\u2019s already contributed a great #GTMTips guest post. It\u2019s great to have him back here sharing his insight on working with Accelerated Mobile Pages (AMP). So, we\u2019re back on AMP! Simo wrote a long, sprawling [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=124426\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-03-10T15:29:44+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/amp_cookies.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2030\" \/>\n\t<meta property=\"og:image:height\" content=\"1074\" \/>\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=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=124426#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=124426\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"Google Analytics Client ID In AMP Pages\",\"datePublished\":\"2025-03-10T15:29:44+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=124426\"},\"wordCount\":2078,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=124426#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/amp_cookies.jpg\",\"keywords\":[\"Amp\",\"Analytics\",\"client\",\"Google\",\"pages\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=124426#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=124426\",\"url\":\"https:\/\/fivemor.com\/?p=124426\",\"name\":\"Google Analytics Client ID In AMP Pages - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=124426#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=124426#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/amp_cookies.jpg\",\"datePublished\":\"2025-03-10T15:29:44+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=124426#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=124426\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=124426#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/amp_cookies.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/amp_cookies.jpg\",\"width\":2030,\"height\":1074},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=124426#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Google Analytics Client ID In AMP Pages\"}]},{\"@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":"Google Analytics Client ID In AMP Pages - 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=124426","og_locale":"en_US","og_type":"article","og_title":"Google Analytics Client ID In AMP Pages - Som2ny Network","og_description":"This article is a collaboration between Simo and Dan Wilkerson. Dan\u2019s one of the smartest analytics developers out there, and he\u2019s already contributed a great #GTMTips guest post. It\u2019s great to have him back here sharing his insight on working with Accelerated Mobile Pages (AMP). So, we\u2019re back on AMP! Simo wrote a long, sprawling [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=124426","og_site_name":"Som2ny Network","article_published_time":"2025-03-10T15:29:44+00:00","og_image":[{"width":2030,"height":1074,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/amp_cookies.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=124426#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=124426"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"Google Analytics Client ID In AMP Pages","datePublished":"2025-03-10T15:29:44+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=124426"},"wordCount":2078,"commentCount":0,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=124426#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/amp_cookies.jpg","keywords":["Amp","Analytics","client","Google","pages"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=124426#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=124426","url":"https:\/\/fivemor.com\/?p=124426","name":"Google Analytics Client ID In AMP Pages - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=124426#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=124426#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/amp_cookies.jpg","datePublished":"2025-03-10T15:29:44+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=124426#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=124426"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=124426#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/amp_cookies.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/amp_cookies.jpg","width":2030,"height":1074},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=124426#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"Google Analytics Client ID In AMP Pages"}]},{"@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\/124426","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=124426"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/124426\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/124427"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=124426"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=124426"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=124426"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=124426"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=124426"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}