Track event in google analytics upon clicking form submit

JavascriptJqueryGoogle AnalyticsAnalytics

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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][1] (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;

[1]: https://developers.google.com/analytics/devguides/collection/analyticsjs/sending-hits#hitcallback "Google Analytics - Sending Data to Google Analytics"

Solution 2 - Javascript

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.

Solution 3 - Javascript

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)

Solution 4 - Javascript

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();
		}
	);
});

Solution 5 - Javascript

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);
});

Solution 6 - Javascript

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();
}

Solution 7 - Javascript

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

Solution 8 - Javascript

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

Solution 9 - Javascript

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).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionat.View Question on Stackoverflow
Solution 1 - JavascriptfluView Answer on Stackoverflow
Solution 2 - JavascriptYahelView Answer on Stackoverflow
Solution 3 - JavascriptDmytro PastovenskyiView Answer on Stackoverflow
Solution 4 - JavascriptepocsquadronView Answer on Stackoverflow
Solution 5 - JavascriptlonesomedayView Answer on Stackoverflow
Solution 6 - JavascriptjsalvataView Answer on Stackoverflow
Solution 7 - JavascriptTom SöderlundView Answer on Stackoverflow
Solution 8 - JavascriptTusharView Answer on Stackoverflow
Solution 9 - JavascriptAlexander FilatovView Answer on Stackoverflow