Html5-boilerplate: 使用 localStorage 进行 Google Analytics 跟踪(如果可用)

创建于 2013-10-07  ·  30评论  ·  资料来源: h5bp/html5-boilerplate

TL;博士:

(function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;
e=o.createElement(i);r=o.getElementsByTagName(i)[0];
e.src='//www.google-analytics.com/analytics.js';
r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
ga('create','UA-XXXXX-X',{'storage': 'none','clientId':localStorage.getItem('gaClientId')});
ga(function(t){localStorage.setItem('gaClientId',t.get('clientId'));});
ga('send','pageview');

来源:
http://stackoverflow.com/questions/4502128/convert-google-analytics-cookies-to-local-session-storage/19207035?noredirect=1#19207035

谷歌分析文档:
https://developers.google.com/analytics/devguides/collection/analyticsjs/domains#disableCookies

我们可以使用Modernizer.localstorage来检查对localStorage的支持,如果它不可用则回退到 cookie。 虽然我不确定我们是否想将 Modernizr 锁定为依赖项。

为什么?
因为对于您的域(或他们的域)的每个请求,谷歌不需要将他们的 cookie 发送到您的服务器。

new feature

最有用的评论

更新:

使用 localStorage 存储 ClientID 不违反 TOS; 它现在由 Google 正式支持: https ://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id#using_localstorage_to_store_the_client_id

注意:如果您必须支持(非常)旧浏览器(如 iOS5 和 FF4),他们的示例代码段可能会失败(请参阅:https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage. js)。

所有30条评论

虽然我不确定我们是否想将 Modernizr 锁定为依赖项。

也许最好将它添加到文档中?

另外,ping @mathiasbynens。

感谢您优化剪辑,大卫。 作为@alrra ,我认为我们很适合将其添加到文档中。

功劳不属于我; @elmerbulthuis 引起了我的注意。 虽然我不会真的认为这是对_snippet_本身的优化,但它本身更像是对整个网络的优化:-p。

我想知道如果每个人都采用localStorage解决方案,可以在全球范围内节省多少字节。

我显然是这个解决方案的忠实粉丝。 默认情况下将其包含在样板文件中的唯一问题是@davidmurdoch提到的问题:我们需要首先对localStorage进行功能测试。 这可以通过使用 Modernizr 或添加一小段独立代码来完成,但无论哪种方式,它都会略微增加页面大小。 再说一次,从长远来看,它将节省许多字节,因为不会在受影响域上的任何资源的请求标头中发送任何 cookie。

像这样的东西:

(function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;
e=o.createElement(i);r=o.getElementsByTagName(i)[0];
e.src='//www.google-analytics.com/analytics.js';
r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
(function(){var a=(function(){var c=new Date,b;try{
localStorage.setItem(c,c);b=localStorage.getItem(c)==c;
localStorage.removeItem(c);return b&&localStorage}catch(d){}}());
ga('create','UA-XXXXX-X',a?{storage:'none',clientId:a.gaId}:{});
ga(function(b){a.gaId=b.get('clientId')});ga('send','pageview')}());

(它使用来自 http://mathiasbynens.be/notes/localstorage-pattern 的localStorage功能测试。)

经过一些快速测试后,它似乎工作正常。 在对此进行更广泛的测试后,我将创建一个 PR。 (当然欢迎帮助!)

仅供参考:对于受影响域的每个请求,这有可能在每次往返中节省大约 33 个原始字节(标头/cookie 未压缩)。

@mathiasbynens '当前的内联特征检测解决方案是 130 个压缩字节 * 更大(显然这对于​​每个唯一页面都会有所不同,但它给了我们一个粗略的想法)。 所以,我们可能应该看看我们是否可以把它打得更低一点。

我个人希望将 gzip 压缩后的差异缩小到 65 个字节,并且我很快就会自己试一试。 :-)

_∗使用这个deflator: http ://www.vervestudios.co/projects/compression-tests/snippet-deflator_

318 GZIPped 字节(我们当前的版本是 248 GZIPped 字节):

(function(l,e){GoogleAnalyticsObject='ga',(window.ga||(ga=function(l,e){(ga.q=ga.q||[]).push(arguments)})).l=+new Date,l=document.createElement('script'),l.src='//www.google-analytics.com/analytics.js',(e=document.getElementsByTagName('script')[0]).parentNode.insertBefore(l,e);ga('create','UA-XXXXX-X',(function(l,e){try{l=(localStorage[ga.l]=ga.l)==ga.l;localStorage.removeItem(ga.l);return l}catch(l){}}())?{storage:'none',clientId:localStorage.clientId}:{});ga(function(l,e){localStorage.clientId=l.get('clientId')});ga('send','pageview')}())

这没有经过很好的测试,所以我仍然需要这样做。 但它是一个开始。

不幸的是, localStorage测试可能在某个浏览器中的某个地方受到损害,因为我摆脱了setItemgetItem调用并使用了其他一些高尔夫“技巧”。

这就是我现在所得到的。 :-)

我突然想到我们一直在压缩片段本身,这有点毫无意义。 Gzip 结果取决于文档的其余部分(即,如果 HTML 源文件内联在文档中,或者 JavaScript 文件的其余部分,如果它是其中的一部分)。 也许仅比较片段的压缩大小不是衡量这一点的最佳方法?

你的片段看起来不错。 很好地重新使用ga.l时间戳而不是生成新时间戳!

不幸的是, localStorage测试可能在某个浏览器中的某个地方受到了损害,因为我摆脱了 setItem 和 getItem 调用并使用了其他一些高尔夫“技巧”。

如果是这样的话,恕我直言,这将是一个交易破坏者。

当 Firefox < 9 支持不再是问题时,我们可以将document.getElementsByTagName('script')[0]替换为document.scripts[0]

@mathiasbynens GZIPing 只是片段将近似于压缩节省的 _minimum_ 字节。 因此,这并不完全是一个有争议的问题。 在几乎所有情况下,片段的压缩率都会随着页面大小的增加而增加。

还需要测试! 我添加了getItemsetItem调用,并设法将其减少到 309 字节:

+function(l,e){(ct=this[GoogleAnalyticsObject='ct']||function(l,e){(ct.q=ct.q||[]).push(arguments)}).l=+new Date,l=document.createElement('script'),l.src='//www.google-analytics.com/analytics.js',(e=document.getElementsByTagName('script')[0]).parentNode.insertBefore(l,e);try{localStorage.setItem(ct.l,ct.l),l=localStorage.getItem(ct.l)-ct.l,localStorage.removeItem(ct.l)}catch(l){};ct('create','UA-XXXXX-X',l?{}:{clientId:localStorage.clientId,storage:'none'}),ct(function(l,e){localStorage.clientId=l.get('clientId')}),ct('send','pageview')}()
  • 我现在使用的 IIFE 使用+符号而不是括号。
  • 我也使用localStorage.clientId而不是localStorage.gaId因为clientId节省了一些字节。
  • 使用this而不是window节省了 1 个字节(结合移动GoogleAnalyticsObject分配)。
  • ga更改为ct (ct 更普遍)节省了一个字节(这可能不值得混淆)。
  • 摆脱函数调用并重用l进行localStorage检查通过将其分配给0成功节省了一堆字节。

同样,这需要更多的测试。

@davidmurdoch测试有什么更新吗? 我们可以为此写一个测试流程,以便其他人可以帮助测试吗?

抱歉,我一直是 MIA,我被安排在一个高优先级的 6 个月项目上,无法将太多时间投入到其他任何事情上。

测试这一点的最简单(也是最愚蠢)的方法是用这个新代码替换你的分析代码,看看你在数字和浏览器版本上是否有任何奇怪的波动。 我自己做过这个,没有看到任何突出的东西。 但是,无论如何,我没有多少oldie访问者。

另一种方法是在生成的 iframe 中加载这个实验性分析脚本(以免干扰稳定的分析代码段),并从那里调用_trackPageview ,当然,在不同的 GA 帐户下。 然后你只需要在一周左右后比较数据。

我不能保证我可以在短期内制作一个用于测试的插入式代码段; 如果其他人想在我躲藏起来时掌握这些想法,请继续。 :-)

我刚刚开始对http://drublic.github.io/css-modal/ 进行测试。 上个月我获得了 97k 的页面浏览量,但在浏览器中广泛传播。

号码:

  1. 铬 44.01%
  2. 火狐 34.38%
  3. 互联网浏览器 8.86%
  4. 歌剧 5.26%
  5. 野生动物园 4.01%
  6. 安卓浏览器 2.22%

让我们等着看。 我得到了并行运行的“正常”统计数据。

除此之外,我认为代码需要更多更新以提高可读性(每行 80 个字符以及插入标识符的位置)。

我将在大约一周后回到这个测试。

我有点早,但我的发现目前相当稳定。 不幸的是,我发现两个帐户的访问者数量存在很大差异。

默认实现显示 3 月 13 日至 17 日的2,964 次唯一访问
基于本地存储的数据显示同一时间范围内的756 次唯一访问

可能有三个可能的原因:

  • 我的剪辑实现已损坏
  • 加载 iframe 被浏览器阻止
  • snipped 的本地存储集成被破坏

目前我在这里的代码中没有看到任何错误:http: //drublic.github.io/css-modal/test-gau-localstorage.html (这是已集成在站点中的 iframe)。

此外,我还没有遇到过 iframe 被浏览器或页面阻止的情况。 有谁知道这是否会发生?

这使我找到了本地存储 GUA 剪断的解决方案存在错误。 我还没有研究可能是什么问题。
我们可以开发一个未缩小的变体以进行进一步测试并在我们找到可行的解决方案后最小化吗?

另外,如果我们找到解决方案,我会选择从 HTML5BP v5.0 对此进行描述,并在 5.1 中发布它。 你们有什么感想?

此外,我会选择从 HTML5BP v5.0 对此进行描述,并在 5.1 中发布它

@drublic :+1: (向 v5.1.0里程碑添加了问题)。

如果您的数字不正确,则可能是您在调用ga('create', w/ storage:'none'必须提供默认的clientId。

https://developers.google.com/analytics/devguides/collection/analyticsjs/domains#disableCookies

刚刚在我的网站上写了关于这个问题的博客,在这里: Google Async Analytics using LocalStorage并在此处设置了一个测试页面:http: //davidmurdoch.com/google-async-analytics-using-localstorage-test/。

请阅读、分享和测试。

(注意:如果您在这些页面上发现任何拼写错误或错误,请在 twitter @pxcoach上告诉我。

嘿,很抱歉聚会晚了一点。 我在 Google Analytics 团队工作,我想就这个问题发表评论并提出我的想法。

首先,我认为 H5BP 项目推荐一个与官方推荐的功能不同的 Google Analytics 跟踪代码段不是一个好主意。 人们可能会认为它们是相同的,如果实际上不是,则会引起混淆。 如果 Google Analytics 文档声称 GA 支持某些功能,但并不是因为有人使用了不同的代码段,那可能会导致一些非常难以调试的问题(特别是如果 H5BP 没有明确表明代码段不同)。

如果 GA 有什么可以做得更好的地方,我们很乐意随着社区的需求而发展,而不是偏离它。 (顺便说一句,在任何与 GA 相关的 Github 问题上,请随时 ping 或抄送我。)

无论如何,这是 localStorage 的主要问题以及为什么 GA 不提供它作为默认存储机制:

localStorage 的范围为location.origin ,而 cookie 的范围为顶级域。 Cookie 存储允许 analytics.js 开箱即用地进行子域跟踪,而这在 localStorage 中是不可能的。 此外,如果您的网站的一部分是 HTTP 而其他部分是 HTTPS,那也会失败(失败是指存储不共享,因此您会丢失客户端 ID,GA 会将其视为单独的会话)。 虽然这些对于大多数 GA 用户来说确实不是问题,但我仍然认为,由于我刚刚描述的功能丢失,将这个提议的片段作为替代品提供是不好的。

话虽如此,基于这个问题和@davidmurdoch的博客文章,我们将尝试优先构建官方支持的localStorage 机制。 目前storage参数只支持选项cookienone ,但我们想添加第三个localStorage选项,所以不支持的用户需要子域或跨方案跟踪可以选择加入。我不知道什么时候会添加,但我可以在/如果是的话更新这个问题。

这对每个人来说都是合理的吗?

@philipwalton感谢您的评论!

这对每个人来说都是合理的吗?

抄送: @davidmurdoch@mathiasbynens

话虽如此,基于这个问题和@davidmurdoch的博客文章,我们将尝试优先构建官方支持的localStorage 机制。

:+1:

添加此问题后,请更新问题。 谢谢!

@philipwalton ,:+1:好消息! 但是,您不需要_尝试_来构建它,我们已经做到了! :-p (我孩子,我孩子)。

我将继续用这个消息更新我的博客文章,并使用非官方的localStorage跟踪代码创建一个 GitHub 存储库,确保强调它的缺点。 谢谢!

:+1: 但未来的网络似乎也需要某种topLevelStorage 。 很高兴该选项将可用。 考虑到这一点,当片段进入时,h5bp 的偏好可能是什么?

@jonathantneal ,我们在 Firefox 中有globalStorage ,它可以跨方案、端口和子域存储。 Firefox 是唯一一个实现它的,它已经被标记为过时了。 :-(

@davidmurdoch 非常感谢您打开这个问题并深入研究它,我们真诚地感谢它!

@philipwalton再次感谢您加入讨论,就像@mathiasbynens所说,请让我们保持最新状态!

并使用非官方的 localStorage 跟踪代码创建 GitHub 存储库,确保强调其缺点。

@davidmurdoch的存储库是https://github.com/davidmurdoch/ga-localstorage(虽然它还没有更新)。

我刚刚将“使用 localStorage 的 Google Analytics”脚本发布到 npm: https ://www.npmjs.org/package/ga-localstorage

https://github.com/davidmurdoch/ga-localstorage repo 也更新了代码。

你好,你看过这个SO评论吗?

http://stackoverflow.com/questions/4502128/convert-google-analytics-cookies-to-local-session-storage/19207035#comment -44767913

我很想知道你们的想法。

@caesarsol我认为这是一个非常糟糕的主意。 正如我在评论中所描述的,cookie 和 localStorage 没有相同的限制,因此将它们换成页面上运行的每个脚本是非常危险的。

你好@philipwalton ,感谢您的回复,但也许我解释得不好,我指的是SO用户_smhmic_的评论:

这可能违反 GA TOS! 这是来自 GA 团队成员的二手报价,摘自这篇文章:“使用 HTTP 状态管理机制”(阅读:localStorage)“传播 cookie 状态是对我们隐私保护措施的规避。这样做违反了 Google Analytics 服务条款”。 我对此的解释是,GA 使用 cookie 而不是 localStorage,因为更多的用户熟悉 cookie 的概念以及如何清除它们; 因此,GA 使用 cookie 是一项隐私功能。 - smhmic

使用 HTTP 状态管理机制”(阅读:localStorage)传播 cookie 状态是对我们隐私保护措施的规避。这样做违反了 Google Analytics 服务条款

嗯,我不认为这是真的。 GA 提供了一些不依赖于使用 cookie 的实施者的退出功能(例如 Chrome 扩展)。 我认为 TOS 的这一部分的要点是,您不能创建一种机制,通过该机制,使用官方“不跟踪”扩展程序的人仍然会被跟踪。

我可以进一步研究它,如果我的假设被证明是错误的,我会更新这个线程。

更新:

使用 localStorage 存储 ClientID 不违反 TOS; 它现在由 Google 正式支持: https ://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id#using_localstorage_to_store_the_client_id

注意:如果您必须支持(非常)旧浏览器(如 iOS5 和 FF4),他们的示例代码段可能会失败(请参阅:https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage. js)。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

greenchili picture greenchili  ·  20评论

roblarsen picture roblarsen  ·  10评论

roblarsen picture roblarsen  ·  5评论

necolas picture necolas  ·  44评论

amilajack picture amilajack  ·  19评论