Code to disable Google Analytics / Adwords cookie until user confirms they accept cookies? - cookies

I found this previous question but I was wondering if there are other ways I could delay GA setting the cookies? That code wasn't clear to me at all, so I'm suspicious of it. How sensitive is the analytics code to being tampered with? Google suggests the code needs to be the first thing in the head tag, so I'm wondering if modifications to it would interfere with its functionality?
The code looks like this:
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-**********"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-**********');
</script>
The code for Adwords is similar:
<script async src="https://www.googletagmanager.com/gtag/js?id=AW-1068746090"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'AW-1068746090');
</script>

Google suggests the code needs to be the first thing in the head tag, so I'm wondering if modifications to it would interfere with its functionality?
Actually it does not matter where you put the code. The earlier/higher you put it the earlier the browser will load it, execute it and send a pageview.
If you prefer page performance (e.g. web core vitals) over misleading tracking, you can replace the async attribute with a defer attribute which will cause GA to load later (e.g. after your page is "ready").
I prefer deferring GA. For us there is no point in measuring pageviews which bounce even before the page is "ready".
Please take into consideration that if you use both - GA4 and AW - the code would look like
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXX');
gtag('config', 'AW-00');
</script>
You do not include it twice.
There's documentation from Google for Consent Mode and about Privacy
Your code would look like this:
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied'
});
gtag('js', new Date());
gtag('config', 'G-XXX');
gtag('config', 'AW-00');
</script>
And here's a brief walkthrough:
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXX"></script>
This loads the tracking code/library. Once it is loaded, it will override the dataLayer.push method and process all entries of the dataLayer array (if there are any). If you would only have this line of markup, nothing would happen. No cookies, no tracking.
window.dataLayer = window.dataLayer || [];
This is some precaution. We cannot be sure if the tracking code/library has been loaded and executed (and declared the dataLayer variable), so we check if dataLayer is undefined. If is undefined we initialize it as an empty array.
function gtag(){dataLayer.push(arguments);}
For easier usage and/or branding we wrap the dataLayer.push() method call in a function called gtag. You could use cl22 or timw instead, it would not matter.
gtag('consent', ...
If you would inspect dataLayer now, it would look like this:
[
[
"consent",
"default",
{
"ad_storage": "denied",
"analytics_storage": "denied"
}
]
]
If push method was already overridden by GA4, this would have been already executed. If not it would sit there and wait until GA4 loads.
gtag('js', new Date());
This creates a timestamp.
gtag('config', 'G-XXX');
This will initialize tracking. In default setups, this will send a page_view event. Here GA4 would set its cookies, but because of our previous "entry" it won't.
gtag('config', 'AW-00');
This will initialize AdWords.

Related

Disabling cookies in Google Analytics - gtag.js

I am looking for a way to disable the cookies set by Google Analytics.
I found some infos in Google's devguides:
https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id#disabling_cookies
Here it says that I should add the following code:
ga('create', 'UA-XXXXXXXXX-X', {
'storage': 'none'
});
But where exactly?
I already tried to add it inside the tracking code:
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-X"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-XXXXXXXXX-X');
ga('create', 'UA-XXXXXXXXX-X', {
'storage': 'none'
});
</script>
I'm grateful for every clue.
Given you use gtag.js (based on your example):
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied'
});
gtag('config', 'xxx');
https://developers.google.com/tag-platform/devguides/consent#set_consent_defaults
storage: 'none' is for analytics.js https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id#disabling_cookies
For gtag.js, I think client_storage: 'none' is what you're looking for. It's referenced in a Medium article titled How to use Google Tag Manager and Google Analytics Without Cookies
<!-- Global site tag (gtag.js) - Google Analytics with out cookies -->
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID', {
client_storage: 'none',
client_id: CLIENT_ID,
});
</script>
Two things, you have confused two versions, the ga create and gtag are different versions. Use the gtag one. Your code for this to work is below:
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA- XXXXXXXXX-X"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
window['ga-disable-UA-XXXXXXXXX-X'] = true;
gtag('config', 'UA-XXXXXXXXX-X');
});
</script>
See reference here https://developers.google.com/analytics/devguides/collection/gtagjs/user-opt-out

Integrating Flow JS with Ember JS - Data not Binded

I am trying to integrate FlowJS with EmberJS. I was successful to upload data to server, so, I am good on that part.
I am unsuccessful When trying to bind flow object data with emberJS component to show data via handlebars. For some reason data binding is not working.
Here is an example of the code.
HTML
<script type="text/x-handlebars" data-template-name="index">
{{flow-uploader}}
</script>
<script type="text/x-handlebars" id="components/flow-uploader">
<div class="drop"></div>
<!-- file list -->
{{#each file in flow.files}}
<p>File name: {{file.name}}</p>
{{/each}}
</script>
JS
App = Ember.Application.create({
rootElement: '#main'
});
App.FlowUploaderComponent = Ember.Component.extend({
flow: function(){
return new Flow({
target: 'http://google.com',
testChunks: false
});
}.property(),
initDropZone: function(){
var flow = this.get('flow');
var drop = this.$('.drop')[0];
var $this = this;
flow.assignDrop(drop);
/*flow.on('fileAdded', function(file, flow){
});
flow.on('filesAdded', function(files){
});
flow.on('fileSuccess', function(file,message){
console.log('file success');
});
flow.on('fileError', function(flow, message, chunk){
console.log('file error');
});*/
flow.on('filesSubmitted', function(){
console.log($this.get('flow').files);
//flow.upload();
});
/*flow.on('complete', function(event, flow){
console.log('completed');
});
flow.on('uploadStart', function(event, flow){
console.log('uploading..');
});
flow.on('fileProgress', function(flow, file){
});*/
}.on('didInsertElement')
});
Example can be seen live at http://jsfiddle.net/sisir/qLuobq48/2/
Basically what I am doing here is to save the flow object as component property. files property of flow object is the array of file to be uploaded. Once we drag and drop or select multiple files to upload the files array gets updated. We can see it on the console. The logging code is added via filesSubmitted event.
From the handlebars expression each file is iterated from the files queue. Initially it is empty but later when it gets populated it doesn't show on the html. The data binding is not working for some reason.
In your component logic:
App.FlowUploaderComponent = Ember.Component.extend({
flow: function(){
return new Flow({
target: 'http://google.com',
testChunks: false
});
}.property(),
initDropZone: function(){
var $this = this;
var flow = this.get('flow');
var drop = this.$('.drop')[0];
flow.assignDrop(drop);
flow.on('filesSubmitted', function(){
//for setting a single property
$this.set('flowFiles', flow.files);
//for setting multiple properties
// $this.setProperties({'flowFiles': flow.files, /* etc.. */});
});
}.on('didInsertElement')
});
In your template:
<script type="text/x-handlebars" data-template-name="index">
{{flow-uploader}}
</script>
<script type="text/x-handlebars" id="components/flow-uploader">
<div class="drop"></div>
<!-- file list -->
{{#each file in flowFiles}}
File name: {{file.name}}
{{/each}}
</script>
See JSBin Example
The problem with your JSFiddle simply is(/was) that you referenced a text/plain file as JavaScript. As I asked here, not every file is usable in JSFiddle and GitHub does not like to get misused as pseudo-CDN for lazy people.
In other words: This error
Uncaught ReferenceError: Flow is not defined
is a result of this error
Refused to execute script from 'https://raw.githubusercontent.com/flowjs/flow.js/master/dist/flow.min.js' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.
and can be fixed using
https://rawgithub.com
or the MaxCDN version
http://rawgit.com/
in place of the branch file URl.
Look at the new JSFiddle with all the console.log() statements. The files added, file added and submitted logs in the console are telling me that everything in your code works fine once you got the right file in use. PROTip: Always check your console for errors.

using a famo.us surface to link to another URL

Seems like this should be obvious but...How can you use a famo.us surface as a link to another webpage?
I've tried:
this.fooSurface.on("click", function(){
window.location.replace("www.foo.com");
});
but this doesn't replace the URL, it just puts the new URL on the end of the address currently in the URL bar. window.location.href = "www.foo.com" has the same result.
EDIT: window.location.assign("www.foo.com") and window.location = ("foo") also have the same result. I think this has something to do with this script in the boilerplate index.html:
<script type="text/javascript">
require.config({baseUrl: 'src/'});
require(['main']);
</script>
Use window.location.assign("http://www.foo.com"); instead.
I probably wouldn't use the replace() method personally, as replace() switches the current page's place in the document history with that of the one you provide to the method, which I can't say I've ever found beneficial as a user unless there's a blank intermediary login page or something very specific (and temporary).
Or you can even just use window.location = "http://www.foo.com";
https://developer.mozilla.org/en-US/docs/Web/API/Window.location
I was able to get things working just fine with the boilerplate generator-famous gives you.
The script tag has nothing to do with it. That's configuration for RequireJS to load in the famo.us library with AMD.
var logo = new ImageSurface({
size: [200, 200],
content: '/content/images/famous_logo.png',
classes: ['backfaceVisibility']
});
logo.on('click', function() {
window.location.href ='http://www.google.com';
});
This problem you're having is also not a famo.us problem. It's your Javascript...

Backbone Collection

I was trying to make a Backbone Application with Django at its backend. I was following a Backbone tutorial. I used the following code:
Code
<!doctype html>
<html lang = "en">
<meta charset = "utf-8">
<title>IstreetApp</title>
<link rel="stylesheet" href = "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Book Manager</h1>
<hr />
<div class="page"></div>
</div>
<script type = "text/template" id = "booklist.template">
</script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.10/backbone-min.js"></script>
<script>
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.url = 'http://backbonejs-beginner.herokuapp.com' + options.url;
});
var Books = Backbone.Collection.extend({
url: '/books'
});
var BookList = Backbone.View.extend({
el: '.page',
render: function () {
var that = this;
var books = new Books();
books.fetch({
success: function(books) {
var template = _.template($('#booklist.template').html(), {books: books.models});
that.$el.html(template);
}
})
}
});
var Router = Backbone.Router.extend({
routes: {
'': 'home'
}
})
var bookList = new BookList();
var router = new Router();
router.on('route:home', function () {
bookList.render();
});
Backbone.history.start();
</script>
</body>
</html>
Since the collection is not defined, the success code doesn't execute. I suppose the collection data should come from the server through Django but I am not sure how and in what form. Kindly help. I am pretty much new to backbone and Django.
When you call fetch on your collection, it makes an AJAX request to:
http://backbonejs-beginner.herokuapp.com/books
However, there is no API set up there. Either one of two things needs to happen:
1) you need to modify your code to point to a different URL, one that does have an existing API (perhaps whatever tutorial you are using has such an API)
2) you need to create such an API yourself on yoursever.com (and then make your Backbone code point to that API's URL instead)
Without a server to support it, operations like save and fetch and such in Backbone simply cannot function.
As a side note, Django is a web site framework. While you can use it to create server-side APIs, that's not really Django's focus. Because of this, several good third party libraries exist for doing RESTful APIs (ie. the kind that Backbone likes) in Django; personally I'd recommend either Django REST Framework (I use it and it works great) or TastyPie (never used it, but it's very popular).
When using a backbone collection you need to return a json array of objects from your api url (http://backbonejs-beginner.herokuapp.com/books)
Example
{[{"name":"bookname", "publisher": "penguin"}, {"name":"bookname", "publisher":"penguin"}]}
You'll also want a model for your collection. A model would look like this
Example:
var Book = Backbone.Model.extend({
defaults: {
"name": "",
"publisher": ""
}
});
The way that the collection works is by parsing the json array and turning each object in the array in to a model that you specific (in this instant an individual book with values for the name and publisher).
When you make a .fetch() on your model you are making a GET request, so make sure that your http://backbonejs-beginner.herokuapp.com/books url is prepared to receive GET requests and respond with the json data in the format I specified up top.

Use of functions in Facebook's JavaScript SDK

I got the Facebook login/logout functionality to work, but had to do it with this un-elegant code like this:
<script type="javascript">
function loadfb() {
var e = document.createElement('script'); e.async = true;
e.src = document.location.protocol + '//connect.facebook.net/es_LA/all.js';
document.getElementById('fb-root').appendChild(e);
};
</script>
<body onload="loadfb()">
I plan on putting that Facebook login button on all the pages of the site, so I really don't want to have this function called onload of every page.
Is this function necessary? I don't completely understand what it is for. What is a better way to do this so I can take it out of my onload?
Thanks!
This code is for asynchronous loading of the Facebook JavaScript SDK. What it does is create the tag
<script async scr="https://connect.facebook.net/es_LA/all.js" ></script>
inside the <div id="fb-root"></div> element. While loading the SDK asynchronously is considered better practice, you can leave out this code and manually enter the script tag yourself - eg:
<div id="fb-root"></div>
<script src="http://connect.facebook.net/es_LA/all.js"></script>
<script>
FB.init({
...
});
</script>