Html5-boilerplate: Use localStorage para rastreamento do Google Analytics quando disponível

Criado em 7 out. 2013  ·  30Comentários  ·  Fonte: h5bp/html5-boilerplate

TL;DR:

(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');

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

Documentos do Google Analytics:
https://developers.google.com/analytics/devguides/collection/analyticsjs/domains#disableCookies

Poderíamos usar Modernizer.localstorage para verificar o suporte de localStorage e recorrer a cookies se não estiver disponível. Embora eu não tenha certeza se queremos bloquear o Modernizr como uma dependência.

Por quê?
Porque o Google não precisa enviar o cookie ao seu servidor para cada solicitação ao seu domínio (ou ao deles, nesse caso).

new feature

Comentários muito úteis

Atualizar:

Não é contra o TOS usar localStorage para armazenar o ClientID; agora é oficialmente suportado pelo Google: https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id#using_localstorage_to_store_the_client_id

Nota: se você tiver que suportar navegadores (extremamente) antigos (como iOS5 e FF4), seu trecho de exemplo pode falhar (consulte: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage. js).

Todos 30 comentários

Embora eu não tenha certeza se queremos bloquear o Modernizr como uma dependência.

Talvez seja melhor apenas adicioná-lo aos documentos?

Além disso, ping @mathiasbynens.

Obrigado por otimizar o recorte, David. Como @alrra , acho que somos bons em adicioná-lo aos documentos.

O crédito não me pertence; isso foi trazido à minha atenção por @elmerbulthuis. Embora eu realmente não considere isso uma otimização do próprio _snippet_, por si só --- é mais uma otimização da web como um todo :-p.

Gostaria de saber quantos bytes poderiam ser salvos, globalmente, se todos adotassem a solução localStorage .

Eu sou obviamente um grande fã desta solução. O único problema em incluí-lo por padrão no clichê é o que @davidmurdoch mencionou: precisamos testar o recurso para localStorage primeiro. Isso pode ser feito usando o Modernizr ou adicionando um pequeno pedaço de código autônomo, mas de qualquer forma aumentará um pouco o tamanho da página. Então, novamente, ele economizará muitos bytes a longo prazo, pois nenhum cookie será enviado nos cabeçalhos de solicitação para nenhum recurso no domínio afetado.

Algo assim:

(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')}());

(Ele usa o teste de recurso localStorage obtido em http://mathiasbynens.be/notes/localstorage-pattern.)

Parece funcionar bem depois de alguns testes rápidos. Vou criar um PR depois de testar isso mais extensivamente. (Ajuda bem-vinda, é claro!)

FYI: isso tem o potencial de economizar cerca de 33 bytes brutos (cabeçalhos/cookies não são compactados) por viagem de ida e volta para cada solicitação aos domínios afetados.

A solução atual de detecção de recursos inline do @mathiasbynens é 130 bytes compactados∗ maior (obviamente, isso será diferente para cada página exclusiva, mas nos dá uma ideia aproximada). Então, provavelmente devemos ver se podemos reduzir um pouco mais.

Eu pessoalmente gostaria de ver o diff compactado em 65 bytes e vou tentar em breve. :-)

_∗usando este deflator: http://www.vervestudios.co/projects/compression-tests/snippet-deflator_

318 bytes GZIPped (nossa versão atual é 248 bytes 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')}())

Isso não foi testado muito bem, então ainda precisarei fazer isso. Mas é um começo.

E, infelizmente, o teste localStorage provavelmente está comprometido em algum navegador em algum lugar, já que me livrei das chamadas setItem e getItem e usei alguns outros "truques" de golfe.

Isso é tudo que tenho por enquanto. :-)

Acabou de me ocorrer que estamos compactando o trecho em si, o que é meio inútil. Os resultados do Gzip dependem do restante do documento (ou seja, da fonte HTML, se estiver embutido em um documento, ou do restante do arquivo JavaScript, se for parte de um). Talvez comparar tamanhos compactados com gzip apenas do snippet não seja a melhor maneira de medir isso?

Seu trecho parece bom. Boa pegada reutilizando o timestamp ga.l em vez de gerar um novo!

E, infelizmente, o teste localStorage provavelmente está comprometido em algum navegador em algum lugar, já que me livrei das chamadas setItem e getItem e usei alguns outros "truques" de golfe.

Se for esse o caso, seria um dealbreaker IMHO.

Podemos substituir document.getElementsByTagName('script')[0] por document.scripts[0] quando o suporte do Firefox < 9 não for mais um problema.

@mathiasbynens GZIPping apenas o snippet aproximará a economia de _minimum_ byte da compactação. Portanto, não é inteiramente um ponto discutível. Em quase todos os casos, a taxa de compactação do snippet aumentará à medida que o tamanho da página aumentar.

Ainda precisa testar! Eu adicionei as chamadas getItem e setItem de volta e consegui reduzir para 309 bytes:

+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')}()
  • Agora estou usando um IIFE que usa um sinal + em vez de envolver parênteses.
  • Também estou usando localStorage.clientId em vez de localStorage.gaId , pois clientId economiza alguns bytes.
  • Usar this em vez de window economizou 1 byte a mais (em combinação com a movimentação da atribuição GoogleAnalyticsObject ).
  • Alterar ga para ct (ct é mais prevalente) economizou mais um byte (isso provavelmente não vale a confusão).
  • Livrar-se da chamada de função e reutilizar l para a verificação localStorage atribuindo-a a 0 em caso de sucesso economizou um monte de bytes.

Novamente, isso precisa de muito mais testes.

@davidmurdoch Alguma atualização sobre os testes ainda? Podemos escrever um fluxo de teste para isso para que outros possam ajudar a testar?

Desculpe, eu fui MIA, fui colocado em um projeto de 6 meses de alta prioridade e não pude dedicar muito tempo a qualquer outra coisa.

A maneira mais fácil (e mais burra) de testar isso é apenas substituir seu código de análise por esse novo código e ver se você obtém flutuações estranhas nos números e nas versões dos navegadores. Eu mesmo fiz isso e não vi nada que se destaque. No entanto, eu não tenho muitos visitantes oldie de qualquer maneira.

Outra maneira seria carregar esse script de análise experimental em um iframe gerado (para não interferir no snippet de análise estável) e chamar _trackPageview de lá, em uma conta do GA diferente, é claro. Então você só precisa comparar os dados depois de uma semana ou mais.

Não posso prometer que poderei trabalhar em um snippet drop-in para testar isso tão cedo; se alguém quiser se apropriar dessas idéias enquanto eu volto a me esconder, por favor, vá em frente. :-)

Acabei de iniciar um teste para http://drublic.github.io/css-modal/. Eu obtive 97 mil visualizações de página nos últimos meses, mas espalhado descontroladamente pelo navegador.

Os números:

  1. Chrome 44,01%
  2. Firefox 34,38%
  3. Internet Explorer 8,86%
  4. Ópera 5,26%
  5. Safári 4,01%
  6. Navegador Android 2,22%

Vamos esperar e ver. Eu tenho as estatísticas "normais" rodando em paralelo.

Além disso, acho que o código precisa de mais algumas atualizações para legibilidade (80 caracteres por linha e onde inserir o identificador).

Voltarei a este teste em cerca de uma semana.

Estou um pouco adiantado, mas minhas descobertas são bastante estáveis ​​no momento. Infelizmente vejo grande diferença no número de visitantes para ambas as contas.

A implementação padrão mostra 2.964 visitas únicas de 13 a 17 de março.
O armazenamento local baseado mostra 756 visitas únicas para o mesmo período.

Pode haver três razões possíveis:

  • minha implementação do recorte está corrompida
  • o carregamento do iframe é bloqueado pelos navegadores
  • a integração de armazenamento local do recorte está quebrada

Atualmente não vejo nenhum erro no meu código aqui: http://drublic.github.io/css-modal/test-gau-localstorage.html (que é o iframe que foi integrado no site).

Também não experimentei iframes sendo bloqueados por navegadores ou páginas. Alguém tem ideia se isso pode acontecer?

O que me leva à solução de que o armazenamento local GUA recortado tem bugs. Não pesquisei quais seriam os problemas.
Podemos desenvolver uma variante não minificada para testes adicionais e minimizar depois que pudermos uma solução de trabalho?

Também eu optaria por descoping isso do HTML5BP v5.0 e lançá-lo com 5.1 se encontrarmos uma solução. O que é que vocês acham?

Também eu optaria por descoping isso do HTML5BP v5.0 e lançá-lo com 5.1

@drublic :+1: (adicionado problema ao marco v5.1.0 ).

Se seus números estão tão errados, provavelmente é o fato de você ter que fornecer um clientId padrão ao chamar ga('create', w/ storage:'none' .

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

Acabei de blogar sobre esse problema no meu site, aqui: Google Async Analytics usando LocalStorage e configurar uma página de teste aqui: http://davidmurdoch.com/google-async-analytics-using-localstorage-test/.

Leia, compartilhe e teste.

(nota: se você encontrar algum erro de digitação ou erro nessas páginas, me avise no twitter @pxcoach .

Ei, desculpe chegar um pouco tarde para a festa. Trabalho na equipe do Google Analytics e gostaria de comentar e dar minha opinião sobre esse problema.

Em primeiro lugar, não acho uma boa ideia para o projeto H5BP recomendar um snippet de rastreamento do Google Analytics que seja funcionalmente diferente do oficialmente recomendado. As pessoas provavelmente vão assumir que são iguais e, se não forem, isso causará confusão. Se a documentação do Google Analytics afirma que o GA é compatível com algum recurso e isso não acontece porque alguém está usando um snippet diferente, isso provavelmente levará a alguns problemas muito difíceis de depurar (especialmente se o H5BP não tornar óbvio que os snippets são diferentes).

Se houver algo que a GA possa fazer melhor, adoraríamos evoluir com as necessidades da comunidade em vez de divergir dela. (BTW, sinta-se à vontade para pingar ou me enviar uma cópia em qualquer problema do Github relacionado ao GA.)

De qualquer forma, aqui está o principal problema com o localStorage e por que o GA não o oferece como mecanismo de armazenamento padrão:

localStorage tem como escopo location.origin enquanto os cookies podem ter como escopo um domínio de nível superior. O armazenamento de cookies permite que o analytics.js faça o rastreamento de subdomínio pronto para uso, e isso não seria possível com localStorage. Além disso, se partes do seu site forem HTTP e outras partes forem HTTPS, isso também falhará (e por falha quero dizer que o armazenamento não é compartilhado, então você perderia o ID do cliente e o GA o trataria como uma sessão separada ). Embora seja verdade que essas não sejam preocupações para a maioria dos usuários do GA, ainda acho que seria ruim oferecer esse snippet proposto como um substituto devido à perda de recursos que acabei de descrever.

Dito isto, com base neste problema e na postagem do blog de @davidmurdoch , tentaremos priorizar a construção de um mecanismo localStorage com suporte oficial. Atualmente, o parâmetro storage suporta apenas as opções cookie e none , mas gostaríamos de adicionar uma terceira opção localStorage , para que os usuários que não precisa de rastreamento de subdomínio ou de esquema cruzado pode optar por participar. Não sei quando isso será adicionado, mas posso atualizar esse problema quando/se for.

Isso parece razoável para todos?

@philipwalton Obrigado pelo comentário!

Isso parece razoável para todos?

Cc: @davidmurdoch , @mathiasbynens

Dito isto, com base neste problema e na postagem do blog de @davidmurdoch , tentaremos priorizar a construção de um mecanismo localStorage com suporte oficial.

:+1:

Atualize o problema quando isso for adicionado. Obrigado!

@philipwalton , :+1: Excelente notícia! No entanto, você não precisa _tentar_ para construí-lo, nós já fizemos! :-p (eu brinco, eu brinco).

Vou atualizar minha postagem no blog com esta notícia e criar um repositório GitHub com o código de rastreamento não oficial localStorage , certificando-me de enfatizar suas deficiências. Obrigado!

:+1: mas também parece que a futura web precisa de algum tipo de topLevelStorage . Ainda bem que a opção será disponibilizada. Com isso em mente, e quando o snippet entrar, qual seria a preferência por h5bp?

@jonathantneal , tínhamos globalStorage no Firefox, que fazia armazenamento de esquema cruzado, porta e subdomínio. O Firefox foi o único a implementá-lo e, desde então, foi marcado como obsoleto. :-(

@davidmurdoch Muito obrigado por abrir esta edição e aprofundá-la, agradecemos sinceramente!

@philipwalton Obrigado novamente por participar da discussão e, como @mathiasbynens disse , por favor, mantenha-nos atualizados!

e crie um repositório GitHub com o código de rastreamento localStorage não oficial, certificando-se de enfatizar suas deficiências.

O repositório de @davidmurdoch é https://github.com/davidmurdoch/ga-localstorage(embora ainda não esteja atualizado).

Acabei de publicar o script "Google Analytics usando localStorage" para npm: https://www.npmjs.org/package/ga-localstorage

O repositório https://github.com/davidmurdoch/ga-localstorage também foi atualizado com o código.

Olá, você já leu este comentário SO?

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

Eu estaria curioso para saber o que todos vocês pensam.

@caesarsol Acho uma péssima ideia. Como descrevi em meu comentário , cookies e localStorage não têm as mesmas restrições, portanto, trocá-los por cada script executado na página é extremamente arriscado.

Olá @philipwalton , obrigado pela resposta, mas talvez eu tenha explicado mal, eu estava me referindo a este comentário do usuário SO _smhmic_:

Isso pode violar o GA TOS! Aqui está uma citação de segunda mão de um membro da equipe do GA, extraída deste artigo: "Usar mecanismos de gerenciamento de estado HTTP" (leia-se: localStorage) "para propagar o estado do cookie é uma violação de nossas proteções de privacidade. Isso viola os Termos de Serviço do Google Analytics ". Minha interpretação disso é que o GA emprega cookies e não localStorage porque mais usuários estão familiarizados com o conceito de cookies e como limpá-los; portanto, o uso de cookies pela GA é um recurso de privacidade. – smhmic

Usar mecanismos de gerenciamento de estado HTTP" (leia-se: localStorage) para propagar o estado do cookie é uma evasão de nossas proteções de privacidade. Isso viola os Termos de Serviço do Google Analytics

Hmmm, eu não acho que isso seja verdade. Existem recursos de desativação que o GA fornece (por exemplo, extensões do Chrome) que não dependem do uso de cookies do implementador. Eu acho que o ponto desta seção do TOS é que você não pode criar um mecanismo pelo qual alguém que está usando uma extensão oficial "não rastrear" será _ainda_ rastreado.

Posso pesquisar mais sobre isso e atualizarei este tópico se minhas suposições se revelarem falsas.

Atualizar:

Não é contra o TOS usar localStorage para armazenar o ClientID; agora é oficialmente suportado pelo Google: https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id#using_localstorage_to_store_the_client_id

Nota: se você tiver que suportar navegadores (extremamente) antigos (como iOS5 e FF4), seu trecho de exemplo pode falhar (consulte: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage. js).

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

sideshowbarker picture sideshowbarker  ·  5Comentários

roblarsen picture roblarsen  ·  9Comentários

roblarsen picture roblarsen  ·  5Comentários

alrra picture alrra  ·  18Comentários

roblarsen picture roblarsen  ·  8Comentários