【问题标题】:Loading Google Analytics after page load by appending script in head doesn't always work在页面加载后通过在 head 中附加脚本来加载 Google Analytics 并不总是有效
【发布时间】:2017-08-30 18:50:38
【问题描述】:

在欧盟,有一项 Cookie 法要求您在用户通过点击、滚动或导航等方式表示同意后加载第三方脚本。所以我通过执行一个在文档加载后调用的函数来加载 3 个脚本。这是代码:

问题在于它并不总是有效,也不总是失败。我看到了会话和活动,但我也知道有些访问不会触发脚本,因为当我自己在其他几台计算机上对其进行测试时,并非所有活动都保存在分析中。

我应该在函数中修复什么以使其始终工作?

【问题讨论】:

  • 我不是在寻找仅加载 GA 的解决方案,需要全部 3 个标签。
  • 用另一个例子来说明问题,有些会话记录在 Hotjar 中,但没有出现在 GA 中,反之亦然。

标签: javascript jquery google-analytics


【解决方案1】:
$(document).ajaxComplete(function() {
        var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-XXXXX-X']);
      _gaq.push(['_trackPageview']);

       var loadGoogleAnalytics = function(){
         var ga = document.createElement('script');
           ga.type = 'text/javascript';
           ga.async = true;
           ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';

           var s = document.getElementsByTagName('script')[0];
           s.parentNode.insertBefore(ga, s);
        }
    });

【讨论】:

  • 那么当任何 ajax 完成时,这个函数会设置 loadGoogleAnalytics 函数吗?这没有任何意义。
【解决方案2】:

如果你看过this的帖子,你可以稍微修改一下来达到你想要的效果:

<script type="text/javascript">
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXX-X']);
  _gaq.push(['_trackPageview']);

   var loadGoogleAnalytics = function(){
     var ga = document.createElement('script');
       ga.type = 'text/javascript';
       ga.async = true;
       ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';

       var s = document.getElementsByTagName('script')[0];
       s.parentNode.insertBefore(ga, s);
    }
</script>

然后,只要用户同意您的 Cookie 使用情况显示,只需致电 loadGoogleAnalytics()

【讨论】:

  • 还有 2 个其他脚本(目前),所以我试图将它们全部组织在一个函数调用中。
  • 哇,这太棒了,非常感谢!这是在同意stackoverflow.com/a/70958220/12668719 后加载 Adsense 的方法
【解决方案3】:

其他回复似乎针对的是遗留的 ga.js,而您的问题似乎是针对 analytics.js(当前)。

稍微研究一下analytics.js sn-p,你可以很容易地找到答案(下图,用prettier格式化):

(function(i, s, o, g, r, a, m) {
  i["GoogleAnalyticsObject"] = r;
  (i[r] =
    i[r] ||
    function() {
      (i[r].q = i[r].q || []).push(arguments);
    }), (i[r].l = 1 * new Date());
  (a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
  a.async = 1;
  a.src = g;
  m.parentNode.insertBefore(a, m);
})(
  window,
  document,
  "script",
  "https://www.google-analytics.com/analytics.js",
  "ga"
);

ga("create", "UA-XXXXX-Y", "auto");
ga("send", "pageview");

诀窍很简单:Google 创建一个全局变量GoogleAnalyticsObject,它是一个代表全局 GoogleAnalytics 名称的字符串。你可以看到默认是"ga"

因此,在加载时,您需要创建两个全局变量:GoogleAnalyticsObject 是一个字符串,window[GoogleAnalyticsObject] 是函数(它只是累积事件,我猜这个函数在加载 lib 时被替换)。然后,当您的用户接受 cookie 时,您可以加载库并完成:)

【讨论】:

    【解决方案4】:

    你可以尝试使用这个对我来说很好的功能:

    function loadGoogleAnalytics(trackingId) {
                    var deferred = $q.defer();
    
                    function loadScript() {
                        var scriptId = 'google-analytics';
    
                        if (document.getElementById(scriptId)) {
                            deferred.resolve();
                            return;
                        }
    
                        var s = document.createElement('script');
                        s.id = scriptId;
                        s.innerText = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', '" + trackingId + "', 'auto');";
    
                        // most browsers
                        s.onload = initGA();
                        // IE 6 & 7
                        s.onreadystatechange = function () {
                            if (this.readyState == 'complete') {
                                initGA();
                            }
                        }
    
                        document.getElementsByTagName('head')[0].appendChild(s);
                    }
    
                    $window.initGA = function () {
                        deferred.resolve();
                    }
    
                    loadScript();
    
                    return deferred.promise;
                }
    

    【讨论】:

      【解决方案5】:

      您可以尝试添加以下内容而不是调用.innerHTML()

      //...text above...
      TheAnalyticsScript.text = ['ga-script-string', 'fb-script.string','hotjar.string'].join('\n');
      $('body').append(TheAnalyticsScript);
      

      如果可行,请告诉我。

      【讨论】:

      • 根据文档,脚本需要附加到头部,而不是正文。
      • @frenchie 我明白了。我将它们附加到正文的原因是因为我不确定如果您在 DOM 加载后将某些内容附加到头部,它们是否会起作用;特别是因为您必须在用户同意后加载它们。您是否尝试将body 更改为head。那它有用吗?
      • 好吧,我们试一试;您可以访问该站点并浏览几页以查看会话是否已保存。我以这种方式加载脚本的另一个原因是我可以将自己排除在分析之外。该站点位于 www.goyaphone.eu,我将测试您的解决方案一天,看看它是否有效。
      • @frenchie 我也刚刚读到这个:jspatterns.com/the-ridiculous-case-of-adding-a-script-element。我想你可能想看看那个。请在该网址上结帐选项#4;显然,作者提到这是将新脚本附加到加载的 DOM 中最接近的最佳方法。希望对您有所帮助。
      • 好的,我看看;我在手机上
      【解决方案6】:

      这是我对这个问题的选择。该解决方案只需修补默认脚本以返回函数,然后仅在获得同意后才添加 script 标签。看看:

      // for GoogleAnalytics
      var loadGA = (function(i, s, o, g, r, a, m) {
        i['GoogleAnalyticsObject'] = r;
        i[r] = i[r] || function() {
            (i[r].q = i[r].q || []).push(arguments)
          },
          i[r].l = 1 * new Date();
      
        // call this function after receiving consent
        return function loadGA() {
          a = s.createElement(o),
            m = s.getElementsByTagName(o)[0];
          a.async = 1;
          a.src = g;
          m.parentNode.insertBefore(a, m)
        }
      })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
      
      // for Facebook
      window.fbAsyncInit = function() {
        FB.init({
          appId: 'your-app-id',
          autoLogAppEvents: true,
          xfbml: true,
          version: 'v2.10'
        });
        FB.AppEvents.logPageView();
      };
      
      var loadFB = (function(d, s, id) {
        //- call this function after receiving consent
        return function loadFB() {
          var js, fjs = d.getElementsByTagName(s)[0];
          if (d.getElementById(id)) {
            return;
          }
          js = d.createElement(s);
          js.id = id;
          js.src = "//connect.facebook.net/en_US/sdk.js";
          fjs.parentNode.insertBefore(js, fjs);
        }
      }(document, 'script', 'facebook-jssdk'));
      
      // for HotJar
      var loadHJ = (function(h, o, t, j, a, r) {
        h.hj = h.hj || function() {
          (h.hj.q = h.hj.q || []).push(arguments)
        };
        h._hjSettings = {
          hjid: 1,
          hjsv: 5
        };
      
        return function loadHJ() {
          a = o.getElementsByTagName('head')[0];
          r = o.createElement('script');
          r.async = 1;
          r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
          a.appendChild(r);
        }
      })(window, document, '//static.hotjar.com/c/hotjar-', '.js?sv=');
      
      // finally when you receive the consent
      function onConsentReceived() {
        loadGA();
        loadFB();
        loadHJ();
      }
      
      //- meanwhile you can continue using ga(), hj() whatever here...
      

      每个加载器都可以在它自己的script 标签中,但要确保这些标签的顺序。

      【讨论】:

        【解决方案7】:

        您可以始终包含它,但删除以下行,而不是附加整个分析脚本:

        ga("send", "pageview");
        

        然后,当用户接受 cookie.. 触发分析功能,使用上面的同一行发送信标。除非被明确告知,否则分析实际上不会发送任何数据。这将是您尝试做的最合乎逻辑的方式。

        【讨论】:

        • 我猜负载本身也发送了许多用户可识别数据,这可能违反法律......不过不确定,而且这只适用于谷歌分析,而不适用于 Facebook 或 Hotjar,这可能仍然记录数据(并违反法律)
        • 我可以看到 facebook 具有相同的功能。 FB.AppEvents.logPageView(); 我看不到 hotjar 的代码。脚本本身的加载不会发送或存储有关访问者的任何数据,除非使用信标告知这样做。您只是加载到执行这些信标功能和收集数据类型的库中。我相信法律是关于存储数据的。毕竟,一旦您访问服务器,您就会有效地交出有关您自己的数据。
        • cookie 法只需要通知用户使用了 cookie 以及使用了哪些 cookie 以及为什么。您只需要显示使用 cookie 的通知,如果他们不想继续,则返回。遵守 cookie 法可归结为三个基本步骤: - 通过 cookie 审核了解您的网站设置了哪些 cookie,以及它们的用途 - 告诉您的访问者您如何使用 cookie。 - 获得他们的同意,例如使用 Optanon,并给予他们一些控制权。我总是给予的控制权是离开的选择。
        • 同意!!!我阅读了谷歌分析文档并检查了我的网站网络活动,现在可以确认这种行为....但就法律而言,我仍然怀疑法律是否仅关于 cookie 的存储(或任何存储)它是否还包括跟踪操作...也许您可以提供更多详细信息(或链接到某些文档)
        • 欧盟 cookie 法的问题是它非常模糊。我一直在设置 cookie 并允许访问者在收到 cookie 通知后离开的基础上进行。用户应该接受通知中的条件,但通常他们不接受。没有强制用户在访问网站之前与通知进行交互。这对于英国的许多开发人员来说仍然是一个问题。 See Cookie Law Information
        【解决方案8】:

        想想你的代码做了什么,这个函数:

        1. 创建一个用字符串填充的&lt;script&gt; 元素
        2. 将其添加到&lt;head&gt;

        请注意,&lt;head&gt; 是 afaik 应该仅在初始加载时加载。根据浏览器实现等情况,您的某些访问者的浏览器可能会忽略您在页面加载完成后添加的&lt;script&gt; 标签。

        如果我明白你什么时候想做正确的事:

        1. 在没有跟踪脚本的情况下加载页面
        2. 显示同意模式/弹出窗口
        3. “同意”点击​​触发此功能无需重新加载页面

        注意:许多欧盟网站在 cookie 同意后重新加载页面,因为它们使用后端渲染将带有跟踪的 &lt;script&gt; 标签添加到页面。通常单击“我同意 cookie”,他们会存储 agreed: true 类型的 cookie,该 cookie 会更改其服务器发送的网页。

        如果您不关心重新加载:

        1. 在用户同意时设置 cookie
        2. 重新加载页面
        3. 让您的后端(php/node/ruby/whatever)基于此 cookie 添加脚本标签

        如果你在乎

        更改您的函数以运行跟踪代码,而不是将它们添加到 DOM。

        只需查看跟踪代码并将其分解为易于阅读的代码即可。比如Ga代码其实很简单:

        var ga = document.createElement('script')
        ga.type = 'text/javascript'
        ga.async = true
        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'
        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
        

        然后

        function addTrackers() {
        
        // Execute the tracking things instead of adding them to the DOM
        
        }
        

        【讨论】:

        • 重新加载很糟糕,正在寻找使我的代码正常工作的解决方案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-02
        相关资源
        最近更新 更多