UPDATE
http://jsfiddle.net/musicisair/rsKtp/embedded/result/
Google Analytics sets 4 cookies that will be sent with all requests to that domain (and ofset its subdomains). From what I can tell no server actually uses them directly; they're only sent with __utm.gif as a query param.
Now, obviously Google Analytics reads, writes and acts on their values and they will need to be available to the GA tracking script.
So, what I am wondering is if it is possible to:
rewrite the __utm* cookies to local storage after ga.js has written them
delete them after ga.js has run
rewrite the cookies FROM local storage back to cookie form right before ga.js reads them
start over
Or, monkey patch ga.js to use local storage before it begins the cookie read/write part.
Obviously if we are going so far out of the way to remove the __utm* cookies we'll want to also use the Async variant of Analytics.
I'm guessing the down vote was because I didn't ask a question. DOH!
My questions are:
Can it be done as described above?
If so, why hasn't it been done?
I have a default HTML/CSS/JS boilerplate template that passes YSlow, PageSpeed, and Chrome's Audit with near perfect scores. I'm really looking for a way to squeeze those remaining cookie bytes from Google Analytics in browsers that support local storage.
Use this:
(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');
if(window.localStorage) {
ga('create', 'UA-98765432-1', 'www.example.com', {
'storage': 'none'
, 'clientId': window.localStorage.getItem('ga_clientId')
});
ga(function(tracker) {
window.localStorage.setItem('ga_clientId', tracker.get('clientId'));
});
}
else {
ga('create', 'UA-98765432-1', 'www.example.com');
}
ga('send', 'pageview');
First, I check if localStorage is supported. If it is supported then the 'storage': 'none' option will disable cookies. Now we can set the clientId from localStorage. If it is empty, Google Analytics will generate a new one for us. We save the new (or existing) clientid in localStorage after the tracker loads.
If localStorage is not supported, I just use the regular analytics method. After the initialization I send a pageView via ga('send', 'pageView').
Also, check out this plunk: http://plnkr.co/MwH6xwGK00u3CFOTzepK
Some experimentation in chrome shows that it may be possible to use getters and setters to patch document.cookie for this, something like:
document.__defineGetter__('cookie', function () {
// Replace this with code to read from localstorage
return "hello";
});
document.__defineSetter__('cookie', function (value) {
// Replace this with code to save to localstorage
console.log(value);
});
ga.js (or any other javascript) could run and access cookies as normal, they just would never get passed to the server.
Obviously this will only work in some browsers. Browsers in which it doesn't work will have to fall back to normal cookies.
There's some related ideas in this question: Is it possible to mock document.cookie in JavaScript?
Yes it can be done. You only have to request the __utm.gif with the parameters. The rest of the data is just used for keeping track of the source, session start time and/or previous visits.
You can easily transfer the cookies both ways, so your first approach should work fine.
If your second approach works... not sure. I don't know the ga.js code good enough to estimate wheter that would or would not be easily possible.
There is also a third option, run your own version of ga.js. You are not required to use the Google version.
Can it be done as described above?
Yes
Why hasn't it been done?
the cookies are small, there isn't that much benefit if you use cookieless domains for all your static content
it's less convenient since a lot of browsers don't support it yet
Related
My project is linked with Google Analytics. Now I would like to create a cookie consent pop-up on my website to comply with EU regulations.
Now I see in the EU regulations that the user can select "allow" or "deny". And then you can anonymize Google Analytics. But how does this work internally in my code?
I don't really know how this all works in code, does anyone have examples?
On the internet you will find a lot about how to create the pop-up, but they never go further on how to code everything internally.
Cookies are files at are stored on your computer that the website can access, 3rd party cookies are cookies that other websites can access too. The most basic way of creating a cookie is by using the browsers local storage. Your allow/deny system can be as simple as a true/false value stored globally, use an if statement to check if cookies are allowed or not every time you get or store a value from local storage.
Here are some examples.
// This will store a value/cookie with the id "myKey" and the value "myValue"
Window.localStorage.setItem("myKey", "myValue");
// You can get the value/cookie you stored earlier by using the values ID, in this case it should return "myValue"
Window.localStorage.getItem("myKey");
// To delete a value/cookie do this
Window.localStorage.remove("myKey");
// this is your logic to check if cookies are allowed
let AreCookiesAllowed = true;
if (AreCookiesAllowed === true)
{
// Do things with cookies
Window.localStorage.setItem("theme", "dark");
}
Reference material can be found here.
The use of a web app is to be evaluated statistically. It has been publicly available since spring of this year.
The web app is linked to Google Analytics. The following is done for the own user data collection:
A Unique User ID is created when the web app is called for the first time. It is stored in the localStorage and is compared each time the page is called up again.
if (localStorage.getItem("uuid") === null) {
localStorage.setItem("uuid", get_uuid());
}
function get_uuid() {
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
)
}
This data is written to a database together with other information (concrete page, time, device type, etc.). Users without Javascript or localStorage will not be included; however, they will probably not be able to use the web app correctly anyway.
If I now compare the data from Google Analytics with my own variant, the discrepancy is considerable.
Different users according to Google: about 900
Different users due to UUID: about 400
Additionally about 100 visits (or interactions) without UUID were registered.
Now my question is why these big differences exist. In my opinion, my data collection should be pretty accurate. But maybe I have a thinking error with the approach of the UUID? Or could it be that Google counts quite differently; for example, any robots that don't leave a UUID behind?
Thank you very much for your answers and considerations.
I'm quite sure you have encountered Google Analytics (GA) spam.
This is because GA is JavaScript and your ID is listed in the html source.
So anyone who wants to create spam on your data can use your ID.
Why you ask... When you notice it you see that there are webpages listed you don't know in your GA data, you (the admin) open them and get a virus or worse.
Don't open the webpages...
There are as far as I know two ways to fix it. Regex filter wich is a common way.
All webpages that has refferals from other domains you don't "know" you need to block.
This takes time and is not a good approach.
My method is to pass a dimension from the html to GA.
If that dimension is missing the data is not real.
Your JavaScript probably looks something like:
.....
ga('require', 'linkid', 'linkid.js');
ga('require', 'displayfeatures');
ga('send', 'pageview');
</script>
If we add a dimension which we pick up in GA admin tools
.....
ga('require', 'linkid', 'linkid.js');
ga('require', 'displayfeatures');
ga('send', 'pageview', {
'dimension1': 'FooBar'
});
</script>
Go to admin -> Property (the middle column) and at the bottom you have Dd Custom Definitions.
Open Custom Dimensions and add the dimension you added to the html.
Now you can set up a filter in the view tab of GA admin to only show data with your custom dimension "FooBar".
Any data that does not have this "FooBar" is spam that is not generated from your webpage.
Just remember you need to change all GA JavaScript codes and add the dimension.
You can see this spam (if I'm correct) in the Acquisition -> All Traffic -> Referrals report.
If you see Sources that you don't recognize and looks odd it's most likely the spam.
Before I used this method my Referrals looked something like this, there is about 50 of these fake referrals.
In EU we have this law that requires web pages to request permission to store cookies. Most of us know about cookies and agree to them but still are forced to accept them explicitly everywhere. So I plan to write this add on (ff & chrome) that will automatically add session cookie with standard name that would mean agreement. Just wondering about few things:
1) What should be the name of the cookie? What should be the value? Should I cover only user agreement option? My proposition is
_cookieok=1
the benefit is that it is short, yet descriptive.
2) Should I add only single cookie - the one I suggested above? Many pages do it in different ways already. They use different cookie names and check for different values. I thought maybe use names and values from popular scripts like http://cookiecuttr.com/ but I don't want to increase upload traffic with a number of mostly not needed cookies.
3) Should I differentiate between types of cookies? I have seen here http://demo.cookieconsent.silktide.com/ there are multiple cookie types you can opt-in/opt-out?
4) Does this have chances to become popular or is it better to use something like point 2 - adding multiple values manually?
5) I could probably also remove those cookies after some event (like after all js onload functions have finished) but I could not find proper hook in firefox addons. Plus maybe some people would like to do filtering out of the script on server side so maybe it is better to keep sending the cookie.
Is there something I have not thought about? My suggested code is in case of FF:
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
include: "*",
contentScriptWhen: 'start',
contentScript: 'document.cookie="_cookieok=1;path=/";'
});
Update
To explain how does it work
1) Most sites already compliant to cookie law do something like this:
if ($.cookie('_cookieok') == null) {
$('#cookie-close').on('click', function (evt) {
$.cookie('cookieok', 1, 300);
});
$('.cookie-prompt').show();
}
so if we agree on same name existance of such ff plugin would be possible. If someone does not plugin - site will prompt him. If has site would recognize addon added cookie as their own.
Not too sure what the point of this really is to be honest?
If you're looking to build something that would be used across a portfolio of sites you manage, then you're probably pushing your luck to force a user to install an extension simply to show they accept your cookies. If it's aimed at a wider audience, i.e. potentially anyone using any website, then the other issue you'll have is getting both users to see the benefit of installing another extension and secondly website operators to write the code necessary to detect your cookie and act accordingly.
Most sites seem to be striving to make cookies and the associated obligations under the legislation as unintrusive as possible - requiring installation of an extension & changes to website code seems to be heading in the opposite direction..
Some countries like China is blocking Facebook/Twitter. How to use JavaScript to check whether a website is not accessible?
update:
I am adding a "Share to Facebook" button on a web page. 50% of the visitors are from China and 50% are from outside of China.
For those China visitors, they would never see that Facebook button because it's blocked. I want to use $.hide() or $.empty() to remove the related HTML if I detected that Facebook is blocked. How can I do that?
You can check if loading the facebook SDK is blocked in china (//connect.facebook.net/en_UK/all.js)
If this is the case then you could do something like this:
$.getScript('//connect.facebook.net/en_UK/all.js')
.success(function(){
// do something if facebook is available
});
You need to take care because you need to define a timeout if you want to make a callback for the fail case. I need to check the correct settings later, but currently i don't have time to.
EDIT
Based on the comment of funkybro it would be better to do a JSONP request. Loading the API would inject a butch of code you probably don't need.
So just request e.g.:
$.getJSON('https://graph.facebook.com/feed?callback=?')
.success(function(){
// do something if facebook is available
});
The request will include a failure code because you don't provide at graph node, but knowing that you get an error message from facebook means that it is reachable for the client.
Use jQuery.get like this:
$.get("http://facebook.com").fail(function() {
$(...).hide()
}).done(function() {
$(...).show()
})
Note that this is a cross-site request that will fail for security reasons unless you disable that browser feature.
If that's not possible for you, I suggest you use GeoIP or similar technologies to determine the users origin.
I am using the google auth but keep getting an origin mismatch. The project I am working has sub domains that are generated by the user. So for example there can be:
john.example.com
henry.example.com
larry.example.com
In my app settings I have one of my origins being http://*.example.com but I get an origin mismatch. Is there a way to solve this? Btw my code looks like this:
gapi.auth.authorize({
client_id : 'xxxxx.apps.googleusercontent.com',
scope : ['https://www.googleapis.com/auth/plus.me',
state: 'http://henry.example.com',
'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile'],
immediate : false
}, function(result) {
if (result != null) {
gapi.client.load('oath2', 'v2', function() {
console.log(gapi.client);
gapi.client.oauth2.userinfo.get().execute(function(resp) {
console.log(resp);
});
});
}
});
Hooray for useful yet unnecessary workarounds (thanks for complicating yourself into a corner Google)....
I was using Google Drive using the javascript api to open up the file picker, retrieve the file info/url and then download it using curl to my server. Once I finally realized that all my wildcard domains would have to be registered, I about had a stroke.
What I do now is the following (this is my use case, cater it to yours as you need to)
On the page that you are on, create an onclick event to open up a new window in a specific domain (https://googledrive.example.com/oauth/index.php?unique_token={some unique token}).
On the new popup I did all my google drive authentication, had a button to click which opened the file picker, then retrieved at least the metadata that I needed from the file. Then I stored the token (primary key), access_token, downloadurl and filename in my database (MySQL).
Back on step one's page, I created a setTimeout() loop that would run an ajax call every second with that same unique_token to check when it had been entered in the database. Once it finds it, I kill the loop and then retrieve the contents and do with them as I will (in this case I uploaded them through a separate upload script that uses curl to fetch the file).
This is obviously not the best method for handling this, but it's better than entering each and every subdomain into googles cloud console. I bet you can probably do this with googles server side oauth libraries they use, but my use case was a little complicated and I was cranky cause I was frustrated at the past 4 days I've spent on a silly little integration with google.
Wildcard origins are not supported, same for redirect URIs.
The fact that you can register a wildcard origin is a bug.
You can use the state parameter, but be very careful with that, make sure you don't create an open redirector (an endpoint that can redirect to any arbitrary URL).