Using JavaScript callback to add onclick events for Google Analytics tracking of outbound hyperlink clicks

Jamie Garroch (MVP)PowerPoint Technical Consultant
CERTIFIED EXPERT
Eating, sleeping, breathing PowerPoint and VBA at BrightCarbon
Published:
google-analytics-logo.png

The Challenge

I was developing a new website for a client the other week in WordPress and they asked me if it was possible to track the clicks of the sponsor images they include on their home page. My first port of call was to use the Yoast Google Analytics plugin but for some reason, it didn't work and I wanted finer control of how my events were presented in the Google Analytics (GA) dashboard.

So, I was left wondering how difficult it would be to write some JavaScript to dynamically assign the event push to Google Analytics using the onclick event.

This article describes how I solved that and as it's JavaScript, the solution can be used in any website design.

The Solution

The method relies on the addEventListener() method which attaches an event handler to the chosen document element. A good introduction to this method can be found at w3schools:
http://www.w3schools.com/js/js_htmldom_eventlistener.asp

The syntax for adding the event listener is:
 
document.addEventListener(event, function, useCapture)

Open in new window


So the starting point of the solution creates the event in the bubbling phase:
if (document.addEventListener)
                          document.addEventListener('click', callback, false);
                      else
                          document.attachEvent('onclick', callback);

Open in new window

Note that the attachEvent method is used to create a cross-browser compatible solutuion for browsers that don't support the addEventListener method eg. IE8 and earlier.

Once this is done, whenever a user clicks on the page the function callback will be executed.

So we next need to define what the callback function will do.

The first thing to do is to pass the user's event to the function:
 
function callback(event) {
                        var evt = window.event || event;

Open in new window


Now that we have our event, we need to decide what to do with it based on what type of element in the document was clicked. In this example, the client wanted to detect clicks on text and clicks on images. We need to handle this in different ways because whilst the element can be assigned to a span of text, it cannot be assigned to the  element and we therefore need to look at the parent of that element type.

Before we do that, let's set up two more variables for the outbound URL that has been clicked and the link type that we will record as a the Event Category in Google Analytics:
  var url;
                        var linkType;

Open in new window

Now we have our variables, we'll set up the conditional statement flow to process the clicked element. This first part looks at the element name:

  switch (evt.target.tagName) {

Open in new window

If the user clicked a text anchor element, we want to set the link type to send to GA and set a reference to the element for later:

    case 'A':
                            linkType = "Out:Text";
                            element = event.target;
                            break;

Open in new window

At this point, I'm going to add some debug code so that you can see what's happening in the console window when you run the code. The variable debug allows you to turn off the messages that will be displayed in the console window. Don't forget to remove all the debugging code from your final code. So we now have this:

function callback(e) {
                        const debug = false;
                        var event = window. event || event;
                        var element;
                        var url;
                        var linkType;
                          
                        switch (e.target.tagName) {
                          case 'A':
                            if (debug == true) {console.log ("Clicked element is A");}
                            linkType = "Out:Text";
                            element = event.target;
                            break;

Open in new window

Next we need to handle the IMG element. Recall that this will not have an href attribute so we need to look at the parent node and see if it has an A element link:
 
    case 'IMG':
                            linkType = "Out:Image";
                            element = event.target.parentNode;
                            if (element.tagName != "A"){
                              if (debug == true) {console.log ("Clicked element is IMG but parent is not A");}
                              return;
                              }
                            else {
                              if (debug == true) {console.log ("Clicked element is IMG and parent is A");}
                              }
                            break;

Open in new window

To complete the conditional section, let's add a message if neither text or image links are found:>

    default:
                            if (debug == true) {console.log ("Clicked element is " + element.target.tagName + " so QUIT");}
                            return;
                        }

Open in new window

Now we need to add the GA event but we don't of course want to process events for in-site links. So if our site is at http://mydomain.com and there are links to http://mydomain.com/page and http://external.com then we only want to record GA events for the external link. To do this, we are going to use a regular expression to see if our site domain is in the link's href attribute:

    if (element.href.indexOf(location.host) == -1 && element.href.match(/^http:\/\//i)){

Open in new window

The location.host will return the domain of our site and the /^http:\/\//i part of the match text says "match if the hyperlink starts with http://" and is case insenstive due to the /i part.

If this match is false it means that the link is NOT internal and hence is outbound, and we will exit the function but if true, we will create a shortened version of the URL to use as the GA Event Action by removing the http:// part:
      url = element.href.replace(/http:\/\//i,"");

Open in new window

Let's add another console debug message at this point:

      if (debug == true) {console.log("Sending event to GA for : " + url);}

Open in new window

Depending on the version of Google Analytics tracking code that you are using, you will need to use one or the other of the following lines. We're using the newer Universal GA script (not shown here) so we use the ga method but you may need to comment that out (or delete it) and use the older _gaq.push method.

      //_gaq.push(['_trackEvent', linkType, url, window.location.href]);
                            ga('send', 'event', linkType, url, window.location.href);

Open in new window

To check which version you need, look the the first line of your GA code:

  • function(i,s,o,g,r,a,m) => you're using the newer Universal tracking code
  • var _gaq = _gaq || []; => you're using the older  Traditional tracking code
Finally, another bit of debug code in case the element wasn't processed:
      }
                          else{
                            if (debug == true) {console.log ("Didn't process GA event for : " + element.href);}
                            return;
                            }
                      }

Open in new window


Complete Code

Here it is fully assembled, with shortened variable names. This should be placed in the section of your page(s), after the main GA script that you get from your GA admin view.

<script type="text/javascript">
                      function callback(e) {
                          const debug = false;
                          var e = window.e || e;
                          var el;
                          var url;
                          var lt;
                          
                          switch (e.target.tagName) {
                          	case 'A':
                          		if (debug == true) {console.log ("Clicked element is A");}
                          		lt = "Out:Text";
                          		el = e.target;
                          		break;
                          	case 'IMG':
                          		lt = "Out:Image";
                          		el = e.target.parentNode;
                          		if (el.tagName != "A"){
                          			if (debug == true) {console.log ("Clicked element is IMG but parent is not A");}
                          			return;
                          			}
                          		else {
                          			if (debug == true) {console.log ("Clicked element is IMG and parent is A");}
                          			}
                          		break;
                          	default:
                          		if (debug == true) {console.log ("Clicked element is " + element.target.tagName + " so QUIT");}
                          		return;
                          }
                          
                          if (el.href.indexOf(location.host) == -1 && el.href.match(/^http:\/\//i)){
                          	url = el.href.replace(/http:\/\//i,"");
                          	if (debug == true) {console.log("Sending event to GA for : " + url);}
                          	//_gaq.push(['_trackEvent', lt, url, window.location.href]);
                          	// 'Event Category', 'Event Action', 'Event Label'
                          	ga('send', 'event', lt, url, window.location.href);
                          	}
                          else{
                          	if (debug == true) {console.log ("Didn't process GA event for : " + element.href);}
                          	return;
                          	}
                      }
                      if (document.addEventListener)
                          document.addEventListener('click', callback, false);
                      else
                          document.attachEvent('onclick', callback);
                      </script>

Open in new window


Results

Once this is integrated into your site, you can log into your Google Analytics dashboard and see Events in both the Real Time and Historical views:

In the example code above, I have mapped the attributes and custom parameters as follows:
GA Event Category = "Out:Image" or "Out:Text"
GA Event Action = the shortened URL of the outbound link
GA Event Label = the URL of the page that the outbound link was present

View 1 : Default view when clicking Real Time / Events:


CWP-Real-Time-GA-events.pngView 2 : As above but clicking any item in the the Event Category column to see the Event Labels:

CWP-Real-Time-GA-events-category.pngYou can then see the historical data under Behaviour / Events / Overview:

CWP-Real-Time-GA-events-history.png

Conclusion

Use the JavaScript code above to add Google Analytis Event handling to image and text hyperlinks. You can also modify the code to work with other elements such as DIV etc. The great thing about using the bubbling method is that events will also work for hyperlinks that are added to the document dynamically. The solution is cross-browser compatible and can be used in your WordPress theme or any other website CMS by adding it in the appropriate place to appear in the section.
3
3,580 Views
Jamie Garroch (MVP)PowerPoint Technical Consultant
CERTIFIED EXPERT
Eating, sleeping, breathing PowerPoint and VBA at BrightCarbon

Comments (2)

Jamie Garroch (MVP)PowerPoint Technical Consultant
CERTIFIED EXPERT

Author

Commented:
Hi Jim. I saw that weird hyperlink thing after posting the draft. I didn't put it in there and it appears to be a link to nothing when I checked the source of the page:

<a href="http://" target="_blank">

So, as I don't know how it got there I'm not sure how to delete it but I'll give it a go now.
Jamie Garroch (MVP)PowerPoint Technical Consultant
CERTIFIED EXPERT

Author

Commented:
Thank you Team EE :-)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.