Track event in google analytics upon clicking form submit
Asked Answered
H

9

64

I need to track an event in google analytics when someone fills out a form and clicks submit. The resulting page that comes up is a standard dashboard-type page, so in order to track the event on that page I'd have to pass in the event in the url and then read the url and output the google analytics event tracking javascript code based on it. This is a frequently bookmarked page though and page that is reloaded, clicked back to, etc. So I'd really rather not pass tracking events in the URL and screw up the analytics.

Instead, I'd much rather do something like the following jQuery code on the page with the form:

$('#form_id').submit(function() {
  _gaq.push('_trackEvent', 'my category', 'my action');
});

The problem I fear with the above is that I'm going to miss some events being tracked because immediately after calling that javascript the browser is going to submit the form and go to another webpage. If the utm.gif tracking image isn't loaded in time, I miss the event :(.

Is my fear justified? How do I ensure I don't miss events being tracked?

Havenot answered 3/11, 2010 at 11:30 Comment(1)
You'll miss events, yeah: I've had this problem. If the form is POSTing the info, that POST request will clobber the Google Analytics GET request that reports the event to GA (and result in a cryptic error in the Chrome console—in 11.0.696.65, at least).Davenport
A
18

There are only 2 ways to ensure, 100%, that all form submissions (amongst users who have JS enabled and who don't block GA) is as follows:

  • You can do an AJAX submit, and then not have to worry about the page changing, and thus have all the time in the world for GA to process AND your new page to load in place of the old one.
  • You can force the form to open its action in a new window, thus leaving all background processes on the main page working, and preventing the race condition you're worried about.

The reason for this is that Google Analytics does not have a callback function, so you can't ever be certain you're capturing all of the submits, even if you put a 10 second lag.

Alternately, you can just pass a GET value to the submitted page and setup a check on that page for the value. If its set, you can send a trackEvent call.

Alainaalaine answered 13/11, 2010 at 14:55 Comment(4)
New window is not an option. The AJAX method though, how does that help? How would I be able to open the new page in place of the old one while the google analytics image is being loaded?Havenot
@at it would technically be the same page, just new content loaded in dynamically using JavaScript, depending on the outcome, making it 'feel' like a new page for the end user. But, since the page wouldn't leave before the ga.js is done building the __utm.gif request, there would be no chance of interruption, so this would provide a more accurate view of how many submits are happening.Alainaalaine
@yc thanks, now I understand what you meant. hmm.. The website depends very much on linking, hitting the back button and other things that have made me very conscious of having a separate webpage for each view and action. However, I guess we could change the URL to something like /current_form_page#redirect=new_page. Any ajax submits would just replace the entire <body> with the new page and set the url accordingly. Going to that url directly or reloading though would cause a redirect to the specified page. Not sure what issues would arise, but I'll give you the accepted answer.Havenot
For future Googlers of this problem, google Analytics does now have a callback function. Simply pass an object at the last argument with a hitCallback property that is a function.Coachwork
S
146

Use Google Analytics hitCallback

You can specify a custom callback function on the tracker object.

_gaq.push(['_set', 'hitCallback', function(){}]);

The callback is invoked after the "hit is sent successfully."

If you want to track a click on a submit button and send the form afterwards you can use the following code (uses jQuery) for your event:

var _this = this; // The form input element that was just clicked
_gaq.push(['_set','hitCallback',function() {
    $(_this).parents('form').first().submit(); // Submit underlying form
}]);
_gaq.push(['_trackEvent', 'My category', 'My action']);
return !window._gat; // Ensure that the event is bubbled if GA is not loaded

Or as onclickone liner for your <input type="submit"> element:

onclick="var _this=this;_gaq.push(['_set','hitCallback',function(){$(_this).parents('form').first().submit();}]);_gaq.push(['_trackEvent','My category','My action']);return !window._gat;"

What it does it that it tracks the event My category/My action, uses jQuery to find the underlying form element of the submit button just pushed, and then submits the whole form.

See: Google Analytics - Sending Data to Google Analytics - Hit Callback (thanks supervacuo)

UPDATE If you're using modern analytics.js code with ga() function defined, you can write this as following:

var _this = this;
ga('send', 'event', 'My category', 'My action', {
    'hitCallback': function() {
        $(_this).parents('form').first().submit();
    }
});

return !window.ga;
Salientian answered 17/9, 2012 at 14:34 Comment(12)
This works great, however I've found that I need to clear the callback after it fires with _gaq.push(['_set', 'hitCallback', null]); Else the callback fires again if the user hits the 'back' button and then performs some other operation on the page that causes another _gaq.push. I had to do this on Android to prevent the callback from firing erroneously multiple times.Spitball
This works perfectly well until there is no active internet connection (working in office LAN sans internet, for eg). Once the internet is disconnected, the callback events dont fire!Nagy
@AnandS that's probably because you can't get a response from google... which means the callback will never be called.Mythicize
@CaffeineComa Saved me a ton of debugging!!! Even though Google might not support ga.js anymore, I wonder why they aren't clearing the callback themselves after executeMich
Nice one. Just an additional advice: If user fail to load analytics.js or cannot communicate with GA server correctly, the hitCallback will never fire. You can resolve this problem by adding a setTimeout(), and force browser to redirect/submit after certain seconds. (If the hitCallback was called before this limit, it will simply be ignored). By this way you still cannot send data to Google, but you provide a usable functionality to visitors though.Monoacid
@renfei, are you certain hitCallback will never fire in those cases? The documentation specifies that, "This callback is designed to always be called, either directly after a hit is sent successfully or when it has been determined that a hit cannot be sent or has failed to send." developers.google.com/analytics/devguides/collection/…Jacquetta
@Jacquetta I didn't notice the documentation you mentioned, but I guess in my experiment it just took too long to determine whether a hit can or cannot be sent.Monoacid
It's realy worked. But I want know where I can view track events in goole analitics. There are real time events and I can view events in real time, but after 30 minuts I don't know where view these.Bedmate
@Bedmate Just ask that as a new question. The comments aren't the right place for this.Salientian
How about case when google-analytics.js is blocked? ga is still defined however callback would not work. I've added case below (answer for google analytics universal). Would be great if you would update you answer (that would save time other people). Anyway thanks for that answer!Tolland
@DmytroPastovenskyi That is a crucial point that everyone should be aware of when looking at this answer.Decimeter
How can label be specified in this case?Scarborough
A
18

There are only 2 ways to ensure, 100%, that all form submissions (amongst users who have JS enabled and who don't block GA) is as follows:

  • You can do an AJAX submit, and then not have to worry about the page changing, and thus have all the time in the world for GA to process AND your new page to load in place of the old one.
  • You can force the form to open its action in a new window, thus leaving all background processes on the main page working, and preventing the race condition you're worried about.

The reason for this is that Google Analytics does not have a callback function, so you can't ever be certain you're capturing all of the submits, even if you put a 10 second lag.

Alternately, you can just pass a GET value to the submitted page and setup a check on that page for the value. If its set, you can send a trackEvent call.

Alainaalaine answered 13/11, 2010 at 14:55 Comment(4)
New window is not an option. The AJAX method though, how does that help? How would I be able to open the new page in place of the old one while the google analytics image is being loaded?Havenot
@at it would technically be the same page, just new content loaded in dynamically using JavaScript, depending on the outcome, making it 'feel' like a new page for the end user. But, since the page wouldn't leave before the ga.js is done building the __utm.gif request, there would be no chance of interruption, so this would provide a more accurate view of how many submits are happening.Alainaalaine
@yc thanks, now I understand what you meant. hmm.. The website depends very much on linking, hitting the back button and other things that have made me very conscious of having a separate webpage for each view and action. However, I guess we could change the URL to something like /current_form_page#redirect=new_page. Any ajax submits would just replace the entire <body> with the new page and set the url accordingly. Going to that url directly or reloading though would cause a redirect to the specified page. Not sure what issues would arise, but I'll give you the accepted answer.Havenot
For future Googlers of this problem, google Analytics does now have a callback function. Simply pass an object at the last argument with a hitCallback property that is a function.Coachwork
T
12

For those who deal with google analytics universal and doing some trick with hitCallback (f.x. track event after validation but before submit of form) keep in mind that google-analytics.js potentially could be blocked, however ga function will be still defined, so submit will not happen.

ga('send', 'pageview', event, {
  'hitCallback': function() {
    _this.submit();
  }
})
return !window.ga;

Can be fixed with validation that check if ga is loaded

ga('send', 'pageview', event, {
  'hitCallback': function() {
    _this.submit();
   }
})
return !(ga.hasOwnProperty('loaded') && ga.loaded === true)
Tolland answered 7/7, 2014 at 14:30 Comment(1)
Is this code supposed to be wrapped inside a function? I don't understand the return statement just hanging there. What am I missing? Thanks.Gundry
A
7

This question is a few years old now, and it seems that google analytics has provided a way to do this without the hacks given above.

From the google analytics docs:

In addition to command arrays, you can also push function objects onto the _gaq queue. The functions can contain any arbitrary JavaScript and like command arrays, they are executed in the order in which they are pushed onto _gaq.

You can combine this with multiple-command pushing to make aboslute sure that they are added in order (and save a call).

$('input[type="submit"]').click(function(e) {
    // Prevent the form being submitted just yet
    e.preventDefault();

    // Keep a reference to this dom element for the callback
    var _this = this;

    _gaq.push(
        // Queue the tracking event
        ['_trackEvent', 'Your event', 'Your action'],
        // Queue the callback function immediately after.
        // This will execute in order.
        function() {
            // Submit the parent form
            $(_this).parents('form').submit();
        }
    );
});
Alagoas answered 1/11, 2012 at 14:40 Comment(5)
Will that work? Looks like it will first track the event, which loads the utm.gif image. Then it will submit the form, but there's still that same chance the form brings you to another page before the utm.gif is loaded (however partially it needs to load to register the event).Havenot
Upon further research, there's some insight from this SO answer which seems to end in uncertainty: #3428080. Regardless of how GA script actually does it, there are some other reccomendations worth looking at on that page.Alagoas
Yet another similar answer that says it's a no: https://mcmap.net/q/277160/-google-analytics-async-events-tracking-callbackAlagoas
Another note: ga debugger does report it as a success before the page is left.Alagoas
This code doesn't work as function will be executed immediately without waiting for event to be trackedHalter
M
6

If you aren't too bothered about 100% accuracy, you could just stick a 1-second delay in.

$('#form_id').submit(function(e) {
  var form = this;
  e.preventDefault(); // disable the default submit action

  _gaq.push('_trackEvent', 'my category', 'my action');

  $(':input', this).attr('disabled', true); // disable all elements in the form, to avoid multiple clicks

  setTimeout(function() { // after 1 second, submit the form
    form.submit();
  }, 1000);
});
Miscreated answered 3/11, 2010 at 11:51 Comment(6)
@at Thinking about it, this will be pretty much 100% accurate, even if the HTTP request is not completed. The key event is that the request is received by the Google servers -- the completion of the HTTP request is only for client feedback. 1 second will give you something very close to 100 accuracy.Miscreated
@Miscreated doesn't this create an infinite loop? Doesn't calling formsubmit() at the end just call this function again and again?Alainaalaine
@yc No, because that's the DOM element's submit action, not the jQuery object's, so it doesn't call the jQuery handlers.Miscreated
@lonesomday ah. you're right about that, but not about 100% accuracy. The latency is with generating the HTTP request. GA doesn't do it immediately. It first has to generate the request in JavaScript. It's usually fast, but again, unpredictable on edge case browsers.Alainaalaine
@yc Interesting -- I'm not particularly familiar with GA, and certainly not with this part of it. I don't quite see how this would alter the point about accuracy -- surely pretty much no browser will take a second to generate an HTTP request.Miscreated
@Miscreated GA sends those events out asynchronously, so there is no way to know when exactly they will be sent. If it has too many events queued, or the browser is busy computing something else, it could be a while. The takeaway is that there is no way to know exactly when the event will be send. This is probably fine for a website's general analytics, but not fine for NASA (or mission-critical statistics).Venerable
S
6

WHile the hitCallback solution is good, I prefer setting a cookie and triggering the event from the next page. In this way a failure in GA won't stop my site:

// Function to set the event to be tracked:
function setDelayedEvent(category, action, label, value) {
  document.cookie='ev='+escape(category)+'!'+escape(action)+'!'+escape(label)+'!'+value
      +'; path=/; expires='+new Date(new Date().getTime()+60000).toUTCString();
}

// Code run in every page, in case the previous page left an event to be tracked:
var formErrorCount= formErrorCount || 0;
var ev= document.cookie.match('(?:;\\s*|^)ev=([^!]*)!([^!]*)!([^!]+)!([^!]+)(?:;|\s*$)');
if (ev && ev.length>2) {
  _gaq.push(['_trackEvent', unescape(ev[1]), unescape(ev[2]),
     unescape(ev[3]), parseInt(ev[4])]);
  document.cookie='ev=; path=/; expires='+new Date(new Date().getTime()-1000).toUTCString();
}
Superposition answered 16/5, 2013 at 7:2 Comment(0)
D
2

This is how you do event callbacks in gtag.js, to ensure Google Analytics data is sent before you change the page URL:

gtag('event', 'view_promotion', { myParameter: myValue, event_callback: function () {
    console.log('Done!');
    // Now submit form or change location.href
} });

Source: https://developers.google.com/analytics/devguides/collection/gtagjs/sending-hits

Durman answered 2/11, 2017 at 9:27 Comment(0)
C
1

Okay since we have moved to Universal analytics, I would like to answer the same using GTM and UA.


GTM:

Track event in google analytics upon clicking form submit is fairly easy using GTM.

  • Create a UA tag and set the type to event in GTM.
  • Fill your desired Event Action, Category and Label
  • Create the trigger of type Form Submission.
  • Put more conditions to target the button you desire

This is the best, optimal and easy going approach for the OP.

enter image description here

Cubiform answered 23/5, 2017 at 5:13 Comment(0)
O
0

When it's crucial that every submit is tracked, I usually set a cookie on the backend with all required data. Then set up a rule in GTM to fire off a tag based on existence of this 1st party cookie. The tag parses the cookie for required values and does whatever is required with them and remove the cookie.

A more complex example is purchase tracking. You want to fire off 5 different tags when user performs a purchase. Race conditions and the immediate redirect to some welcome page make it difficult to rely on simple "onSubmit" tracking. So I set a cookie with all purchase-related data and on whatever page the user ends up on GTM will recognize the cookie, fire off an "entry point" tag which will parse the cookie, push all values to dataLayer, remove the cookie and then the tag itself will push events to dataLayer thereby triggering the 5 tags that require the purchase data (which is already in dataLayer).

Ocd answered 27/11, 2014 at 13:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.