18

We have an ajaxy sort of html based app framework thing and want google analytics to work with it. And I believe we have set things up properly to manually call _trackPageview where needed.

However things don't seem to be getting reported. Now either I don't have it working right, or GA tracking from javascript with a file:// protocol on the url silently violates some cross domain policy I'm not aware of.

So does GA work with local html via file://? Or is there something wrong with my GA usage?

Note that the domain we are using doesn't actually exist. We want to use something like the mobile app tracking but from JavaScript rather than a native library. And in order to do this, it looks you setup a fake domain, and tell the tracker what domain it should be reporting as.


At the end of my <head>:

<script type="text/javascript">
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXACCOUNTID-XX']);
  _gaq.push(['_setDomainName', 'myfake.domain.com']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = 'http://www.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();
</script>

And in our JS framework we call:

_gaq.push(['_trackPageview', '/some/path/here']);
Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • I can see no info hinting that `script` tags work differently on `file://` resources. (Checked [here](https://developer.mozilla.org/En/Same-origin_policy_for_file:_URIs) among other places) but maybe GA blocks this? – Pekka Aug 28 '10 at 18:15
  • Wel in my cases this is webkit powered browsers, primarily. – Alex Wayne Aug 28 '10 at 18:18
  • Do you get an error message in your console? – Marcel Korpel Aug 28 '10 at 19:32
  • No output whatsoever. But I can tell that `_gaq` is an object that looks to be loaded by google analytics with tons of functions. Inlcluding `push()` – Alex Wayne Aug 28 '10 at 19:45
  • Did you already look at GA's [domain & directory settings](http://code.google.com/apis/analytics/docs/gaJS/gaJSApiDomainDirectory.html)? – Marcel Korpel Aug 28 '10 at 21:06
  • I don't think that applies, because I am calling `_trackPageview` directly. – Alex Wayne Aug 28 '10 at 23:14
  • Can you post the query string attached to the _utm.gif request? It will be easier to debug if we can see how the requests are being logged. – Yahel Aug 29 '10 at 12:53

5 Answers5

23

Google now supports disabling the protocol check task by setting it to null, allowing you to track analytics from a file:// url:

ga('create', 'UA-XXXXX-Y', 'auto');
ga('set', 'checkProtocolTask', null); // Disable file protocol checking.
ga('set', 'checkStorageTask', null); // Disable cookie storage checking.
ga('set', 'historyImportTask', null); // Disable history checking (requires reading from cookies).
ga('send', 'pageview');
Community
  • 1
  • 1
Jim Geurts
  • 20,189
  • 23
  • 95
  • 116
9

A couple of tweaks are necessary:

Disable cookie storage

Cookies cannot be used as there's no domain in action, so we need to prevent GA from trying to use them. This is done by setting 'storage': 'none' in creation config (documentation).

Disable file protocol check

By default, GA aborts if the protocol (in our case file) is not http or https. Disable this check using the corresponding task: ga('set', 'checkProtocolTask', null)

Set active page manually

Since there is no domain, GA fails to derive a path denoting the active page. It can be configured manually by using the page URL modification feature: ga('set', 'page', 'foobar')

A subsequent ga('send', 'pageview') will then show up in data as a visit on /foobar.

Track user identity using localStorage (optional)

With cookies disabled, users are not tracked across page loads, so each refresh will trigger detection of another unique visitor. However, we can provide custom client ids on create by setting 'clientId': localStorage.getItem(someKey), which looks for previously stored client ids.

Storing ids is done by

ga(function(tracker) {
  localStorage.setItem(someKey, tracker.get('clientId'));
})

Everything combined

Combining all above steps, we end up with something like the following:

(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-XXXXXXXX-Y', {
    'storage': 'none',
    'clientId': localStorage.getItem('ga:clientId')
});
ga(function(tracker) {
    localStorage.setItem('ga:clientId', tracker.get('clientId'));
});
ga('set', 'checkProtocolTask', null);

ga('set', 'page', 'myPage');
ga('send', 'pageview');
Cedric Reichenbach
  • 8,970
  • 6
  • 54
  • 89
  • 1
    is this possible with gtag? – Naruto26 Nov 13 '19 at 07:44
  • 1
    @Naruto26 did you find way to skip protocol checking it with gtag? With new GA4 and its new properties G-xxxxxxx seem it is not possible. GA4 does not use analytics.js and ga() but just gtag.js + gtag(). – mikep Dec 07 '20 at 08:29
  • @Naruto26 so far this is not possible with GA4, Google didn't give a damn for the [main bug report from 3 years ago](https://issuetracker.google.com/issues/174954288). Good luck. – igorsantos07 Aug 19 '23 at 00:23
3

OK, I think I have this one solved. It's been dogging me for a few days.

According to Google Analytics Help Center,

Visitors must have JavaScript, images, and cookies enabled in their browsers in order for Analytics to report their visit.

Here's my theory: In my tests on Mac OS X Snow Leopard, documents run from file:// are not able to set cookies. This is because cookies are proprietary to HTTP, and when you run something from file://, you're not using the HTTP protocol.

Since you're not able to set cookies, ga.js refuses to send the _utm.gif request to Google's servers. No cookies get set; no request is sent to google, so nothing is logged in GA.

Solution: Use a development environment where you can set your domain as http://localhost (something like MAMP, if you're on a Mac and need a LAMP stack)

(Weird footnote: I observed some weird behavior where the GA cookies would set as third-party cookies of the domain of an unrelated imported script from a third party non-CDN domain. This could be because since the server sends HTTP cookies with the file, ga.js is attaching itself to that domain. However, this won't serve as a backdoor, since it still won't send the _utm.gif hit to Google's servers ).

========

EDIT:

You could try one of the various work arounds people have created for cookie-less GA tracking.

You might get some success out of this tool: http://code.google.com/p/google-analytics-js/downloads/list, explained here: http://remysharp.com/2009/02/27/analytics-for-bookmarklets-injected-scripts/

Instead of all of that GA code, you would include the script, and then call it using the following code:

gaTrack('UA-XXXACCOUNTID-XX', 'myfake.domain.com', '/some/path/here');

Its designed for bookmarklet/injected script tracking, but if I put in a file:// type setup, its able to successfully send the __utm.gif hit, meaning it SHOULD track successfully in GA.

The drawback is that cookieless means that it won't be able to track visits accurately, just page-view level data.

Yahel
  • 37,023
  • 22
  • 103
  • 153
  • I see. And obviously cookies being set for `file://` would be weird, since there is no domain. But in my case running a local server wont really work. I guess I can't use this via JS, dang. – Alex Wayne Aug 30 '10 at 19:53
  • `Visitors must have JavaScript, images, and cookies enabled in their browsers in order for Analytics to report their visit.` Yes, I'd agree a JavaScript script that Google tells everyone to add to their pages, would at least need well, JavaScript support in the browser. – Armen Michaeli Nov 25 '18 at 14:04
1

Ended up with a complex bounce through an iframe via the resize hack message passing mechanism.

Local file include an iframe on our server. When we want to track a GA call we changes it's url hash with the info we need #_trackEvent,foo,bar, and then change the width of the iframe. In the iframe the onresize() function gets triggered and allows us to submit GA calls by inspecting the hash.

As much as I hate this hack, it works flawlessly!

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • Wasn't able to get this to work. Google Analytics requires cookies, and even if you're loading a page through an iframe with the http protocol, GA still has to set the cookie somewhere. The only place it can do that is on your machine, which it can't do because the page ultimately is still on file://. – ehynds Jan 25 '12 at 18:34
  • @ehynds Not true. When a `file://` url has an iframe pointing at `http://someotherserver.com/analytics.html` then that server can set cookies for that domain. The `file://` url can't read those cookies directly, but the JS running in that iframe can. And the `file://` url JS can send messages to that iframe, which is what makes it work. That said though, this solution still sucks. – Alex Wayne Jan 25 '12 at 18:37
  • Right - but ga.js sets the cookies, not the server. When __utm.gif is called, ga.js reads the cookies back and passes them along in the `utmcc` param. Using your method, I see the request for the __utm.gif file going through, but the `utmcc` param is blank, and according to Google this is a [required field](http://code.google.com/apis/analytics/docs/tracking/gaTrackingTroubleshooting.html#basicDebugging). – ehynds Jan 25 '12 at 18:41
-1

here is my code, it works

<script>
function sendData()
{
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'UA-148029185-2');

ga('create', 'UA-148029185-2', {
    'storage': 'none',
    'clientId': localStorage.getItem('ga:clientId')
});
ga(function(tracker) {
    localStorage.setItem('ga:clientId', tracker.get('clientId'));
});
ga('set', 'checkProtocolTask', null);

ga('set', 'page', '/xxxxxxxx');
ga('send', 'pageview');
}
</script>

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-148029185-2" onload="sendData()"></script>
  • 2
    Did you find way to skip protocol checking it with gtag for new GA4 properties? With new GA4 and its new properties G-xxxxxxx seem it is not possible. GA4 does not use analytics.js and ga() but just gtag.js + gtag(). Here https://www.google-analytics.com/analytics.js is checkProtocolTask but here https://www.googletagmanager.com/gtag/js it is not. – mikep Dec 07 '20 at 08:35
  • *"here is my code, it works"* - **nope, it doesn't** – igorsantos07 Aug 19 '23 at 00:26