Can I send a Google Analytics event and immediately navigate away, like so?
_gaq.push(['_trackEvent', 'foobar']);
window.location = "/";
If Google Analytics does some kind of AJAX request when this is called then it should work whether we stay on the page or not. My concern is that it seems it may sometimes just be putting stuff in an array for later processing. I'm thinking this only happens initially, when Google Analytics hasn't had time to be initialized yet, but I'd like to be certain of this.
I did a test with GA debug, and it seemed to have worked, but I'm not sure if that means it always will depending on loading speed and what not.
Can I do this and never lose any events?
The way I've done it is like so:
_gaq.push(['_trackEvent', '...', '...', '...']);
_gaq.push(function(){
// do stuff here
});
$('#logo').on('click', function(){
var curPage = window.location.href;
_gaq.push(['_trackEvent', curPage, '#logo']);
_gaq.push(function(){
window.location.href = '/';
});
});
The second push call will always run after the first one, because Google queues all push calls, so that the first one will run and complete, then the second one will run and complete. Google lets you put functions in the push method so you can queue them.
Source: https://developers.google.com/analytics/devguides/collection/gajs/#PushingFunctions
I add a slight delay (via setTimeout) if the new page isn't being opened in a new window.
I haven't had a chance to try this yet, but Google's new Universal Analytics has a hitCallback function that is executed after the data has been sent.
#mike mentions hitCallback method which is described in analytics.js documentation:
In some cases, like when you track outbound links, you might want to know when the tracker is done sending data. That way you can send a user to their destination only after their click has been reported to Google Analytics. To solve this, the send command allows you to specify a hitCallback function in the field name object that will execute as soon as analytics.js has completed sending data.
Which is fantastic, except the snippet is still in public beta. If for some reason (ahem technophobic policies ahem) you're limited to ga.js functionality, you can use this workaround:
_gaq.push(['_set', 'hitCallback', function(){
document.location='someOtherPage.html';
}]);
_gaq.push(['_trackEvent', 'category', 'event', 'value']);
Another sensible suggestion is to have a fallback to have the callback executed immediately if _gaq is not defined.
It looks like your concern about losing the event is legitimate, see this question. One answer there seems a little fragile with regards to Google changing their code, but would let you confirm the event tracking before navigating to the link. That would probably be "near-immediate".
Related
What I am trying to do is to redirect the user to the next page right after sending an event to Google Analytics:
_gaq.push(['_trackEvent', 'xxx' ...]);
window.location = 'some url ...';
The above code manages to register events because I can see them in the GA report. However I suspect that some events were lost because the browser redirects the user to the new page before the track pixel loads.
My questions are:
Does _gaq.push() block until the event has successfully reached Google's server?
If not, what is the best way to make achieve what I need?
Thanks!
Google has a support page that says you might want to add a delay after calling _gac.push, however they claim that this is to give the Google Analytics JavaScript a chance to load. They don't say that it's to ensure the request is sent.
First, delay the outbound click by a fraction of a second.
This delay will hardly be noticeable by the user, but it will provide the browser more time load the tracking code. Without this method, it's possible that a user can click on the outbound link before the tracking code loads, in which case the event will not be recorded.
I haven't checked #pixelfreak's claim of handling onbeforeunload, but it seems that's what they do.
This is my observation based on some quick research. That function is part of Google Analytic's asynchronous API, so it should not block anything, otherwise, it's not async. :)
Digging through the obfuscated ga.js, you can kinda see that the tracking is probably called onbeforeunload, which fires when you leave a page.
It really doesn't matter if the tracking pixel loads completely, it's a fire & forget. As long as the request is initiated and reaches Google's server, it'll get tracked. The response (in this case, the pixel image) is a by-product.
Maybe you can try this method, but I have not tried
_gaq.push(['_trackEvent', 'xxx' ...]);
_gaq.push(function(){location.reload()});
Just use 1 sec delay. Like this:
_gaq.push(['_trackEvent', 'xxx' ...]);
setTimeout(function(){window.location = 'some_url'}, 1000);
I'd like to have better error page reporting in Google Analytics. Currently, if someone does something on my site which causes a problem, they see an error page instead of the content they expected. The URL remains the same. So if they went to www.example.com/view_my_profile and there was a problem with their profile, they would see an error page at that URL.
What I'd like to do is send Google Analytics a virtual pageview of something like www.example.com/error/view_my_profile/ (maybe an event captures the extra parameters better?). That's easy enough. But I want this virtal pageview to happen instead of the /view_my_profile real pageview. Because that real page wasn't actually viewed and it would be registering an extra pageview on my site.
Is this as simple as leaving out the _trackPageView call in the google analytics snippet below or am I asking for trouble?
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-${gaAccount}-1']);
_gaq.push(['_trackPageview']);
Way over-complicating things..just use _trackPageView like normal but pass a value (virtual URL) to it for the URL you want it to be. It will count as a page view for the URL you pass it instead of the current URL.
You can do this without complication. As long as you load ga.js, instantiate var gaq, and set the account, you can make any calls you want, including _trackPageview with only a virtual pageview value.
You don't even need to call the organic _trackPageview -- you could just do event tracking. In fact, you might want to consider doing an organic pageview, coupled with an Event Tracking that passes some detailed error tracking info to you. Because there can be up to 4 parameters, you can log more and better structured data.
So, on your 404 page, you could call something like:
_gaq.push(['_trackEvent', '404 Error', location.pathname, document.referrer, time_stamp_value]);
(where you've previously defined time_stamp_value as a non-float Number.)
Something that simple will allow you to create hierarchies for your errors, count them more easily, and even do things like the referring page and a timestamp value, without cluttering your pageview information.
I am attempting to track events when links are clicked on my site in a method similar to the following.
Example
<script type="text/javascript">
jQuery(function($) {
// track clicks on all anchor tags that require it
$('a.track').live('click', function(e) {
// send an AJAX request to our event tracking URL for the server to track it
$.get('/events/track', {
url: $(this).attr('href'),
text: $(this).text()
});
});
});
</script>
The problem that I'm having is that a new page load interrupts the AJAX request, and so sometimes these events aren't being tracked. I know Google Analytics has a _trackPageview function that can be attached to onclick events though, and this doesn't seem to be an issue for that. I'm wondering what's different about their call vs. mine that I'm seeing this race condition, and GA isn't. e.g.:
Example
Note that I'm not worried about the result of the AJAX request...I simply want it to ping the server with the fact that an event happened.
(Also, I expect I'll get at least one answer that says to simply track the new page load from the server side, not the client side. This is not an acceptable answer for this question. I'm looking for something like how Google Analytics' trackPageview function works on the click event of anchor tags regardless of a new page being loaded.)
Running Google's trackPageview method through a proxy like Charles shows that calls to trackPageview( ) request a pixel from Google's servers with various parameters set, which is how most analytics packages wind up implementing such pieces of functionality (Omniture does the same).
Basically, to get around ansynchronous requests not completing, they have the client request an image and crunch the parameters passed in those requests on the server side.
For your end, you'd need to implement the same thing: write a utility method that requests an image from your server, passing along the information you're interested in via URL parameters (something like /track.gif?page=foo.html&link=Click%20Me&bar=baz); the server would then log those parameters in the database and send back the gif.
After that, it's merely slicing and dicing the data you've collected to generate reports.
Matt,
If you just want to make sure that the tracking pixel request is made and you don't depend upon response then just doing document.write for the tracking pixel image will do the work.
And you can do the document.write in your onclick handler.
AFA race condition between href and onclick handler of anchor element is concerned the order is well defined.
the event handler script is executed first
the default action takes place afterwards (in this case the default handler is href)
(Source : Href and onclick issue in anchor link)
But yes, if you depend upon the response of the tracking request to the server then you will have to make it synchronous.
Suggested option would be to call some javascript function to wrap the already defined onclick handlers and then in the order make the calls. Make sure that your tracking request is not asynchronous.
Though it is suggested that you should not be dependent upon the response of the tracking pixel request.
I'm implementing click tracking from various pages in our corporate intranet in order to add some sorely needed crowd-sourced popular link features ("most popular links in your department in the last 24 hours", etc.)
I'm using jQuery's .live() to bind to the mousedown event for all link elements on the page, filter the event, and then fire off a pseudo-ajax request with various data to a back-end server before returning true so that the link action fires:
$("#contentarea a").live("mousedown", function(ev) {
//
// detect event, find closest link, process it here
//
$.ajax({
url: 'my-url',
cache: false,
dataType: 'jsonp',
jsonp: 'cb',
data: myDataString,
success: function() {
// silence is golden -- server does send success JSONP but
// regardless of success or failure, we allow the user to continue
}
});
return true; // allow event to continue, user leaves the page.
}
As you can probably guess from the above, I have several constraints:
The back-end tracking server is on a different sub-domain from the calling page. I can't get round this. That's why I am using JSONP (and GET) as opposed to proper AJAX with POST. I can't implement an AJAX proxy as the web servers do not have outbound network access for scripts.
This is probably not relevant, but in the interest of full disclosure, the content and script is inside a "main content" iframe (and this is not going to change. I will likely eventually move the event listener to the parent frame to monitor it's links and all child content, but step 1 is getting it to work properly in the simplified case of "1 child window"). Parent and child are same domain.
The back-end is IIS/ASP (again, a constraint -- don't ask!), so I can't immediately fork the back-end process or otherwise terminate the response but keep processing like I could on a better platform
Despite all this, for the most part, the system works -- I click links on the page, and they appear in the database pretty seamlessly.
However it isn't reliable -- for a large number of links, particularly off-site links that have their target set to "_top", they don't appear. If the link is opened in a new tab or window, it registers OK.
I have ruled out script errors -- it seems that either:
(a) the request is never making it to the back-end in time; or
(b) the request is making it, but ASP is detecting that the client is disconnecting shortly afterwards, and as it is a GET request, is not processing it.
I suspect (b), since latency to the server is very fast and many links register OK. If I put in an alert pop-up after the event fires, or set the return value to false, the click is registered OK.
Any advice on how I can solve this (in the context that I cannot change my constraints)? I can't make the GET request synchronous as it is not true AJAX.
Q: Would it work better if I was making a POST request to ASP? If (b) is the culprit would it behave differently for POST vs GET? If so, I could use a hidden iframe/form to POST the data. however, I suspect this would be slower and more clunky, and might still not make it in time. I wouldn't be able to listen to see if the request completes because it is cross-domain.
Q: Can I just add a delay to the script after the GET request is fired off? How do I do this in a single-threaded way? I need to return true from my function, to ensure the default event eventually fires, so I can't use setTimeout(). Would a tight loop waiting for 'success' to fire and set some variable work? I'm worried that this would freeze up things too much and the response would be slowed down. I assume the jQuery delay() plugin is just a loop too?
Or is something else I haven't thought of likely to be the culprit?
I don't need bullet-proof reliability. If all links are equally catchable 95% of the time it is fine. However right now, some links are catchable 100% of the time, while others are uncatchable -- which isn't going to cut it for what I want to achieve.
Thanks in advance.
I would try a different approach. You can bind to a different event like:
$(window).unload(function(event) {
// tracking code here
});
I would try to return false from the link event handler, remember the URL and navigate away only when JSONP request succeeds. Hopefully it shouldn't add too much latency. Considering you are on the inranet, it might be OK.
Solved!
The short answer is: there is no reliable way to do this cross-domain with a GET request. I tried all sorts, including storing the event and trying to replay the event later, and all manner of hacks to try to get that to work.
I then tried tight loops, and they weren't reliable either.
Finally, I just gave in and used a dynamically created form that POSTed the results, with the target set to a hidden iFrame.
That works reliably -- it seems the browser pauses to finish its POST request before moving on, and ASP honours the POST. Turns out it's not 'clunky' at all. Sure, due to the browser security model I can't see the result... but it doesn't matter in this case.
I am now kicking myself that I didn't try that option first.
My site uses the Google Maps API. In situations where the connection to Google is slow and the map can't be rendered in a reasonable time, I'd like a Javascript callback method to be called such that I can display a useful message to the user rather than have a 'loading...' message constantly displayed.
Is this achievable?
Maybe you could have a sleep function that would check if the page has loaded yet, and after a certain time you take some sort of action.
See this posting for a situation similar to yours
setTimeout might be useful too.
so, you would have:
setTimeout((function()
{ /* test if the page is loaded,
if so, call another function
or set a flag to get out*/
}),2000); //set for 2 seconds