Google Analytics Page Tracking in Grails Web Flow

Google Analytics makes tracking the metrics of a website easy by capturing the url of each page (gaTrackingOverview documentation). This works great for pages that have unique and meaningful urls, but when it comes to tracking pages that are included as part of a Grails web flow, tracking by the url becomes useless.

Grails uses a flow execution key to track the pages in each step of the flow, passing the key around as a parameter on the request. Within a Grails web flow, the url will look something like this http://hostName/appName/controllerName/flowName?execution=e1s2. The execution key isn’t reliable for tracking purposes, and would be meaningless to the person who will be looking at the Google Analytics report data.

Urls With Execution Key image

One word of caution here, once you start tracking data from your website, you can never clear that data from your Google Analytics reports. So if you want to get this setup and test this without affecting up your production reports, start by reading Setting Up Google Analytics on localhost.

Once you have Google Analytics setup, your javascript will look something like this…

<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-xxxxxxxx-x']);
_gaq.push(['_setDomainName', 'none']);
_gaq.push(['_setAllowLinker', 'true']);
_gaq.push(['_trackPageview']);

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

Google Analytics tracks the pageview data using the _trackPageview method (_trackPageview documentation).  The _trackPageview method takes a url as an optional parameter. If you include a value for the url, Google Analytics will record this value as the url that shows up in your reports. Here’s an example of what the javascript would look like if you included an optional url…

<script type='text/javascript'>_gaq.push(['_trackPageview', '/path/pageName']);</script>

To customize the url value for Grails web flow pages, you need to pass in the preferred url for each page in the flow. You could include the line of javascript code on every page in your flow, passing in a different url for each page. But this could be tedious and repetitive. I wanted a less invasive global solution, so I chose to write a Grails tag and include the tag in the <head> of the layout.gsp for our site.

Here is the code for my tag…

class MyTagLib {

static namespace = "bc"

def googleAnalyticsWebflowUrl = { attrs, body ->

//Only include the custom url on pages in a web flow
if (request['flowExecutionKey'])  {
ProgressData progressData = request['progressData']
def currentStep = progressData.currentStep()
def appName = grailsApplication.metadata['app.name']

out << "<script type='text/javascript'>_gaq.push(['_trackPageview', '${appName}/${controllerName}/${actionName}/${currentStep}']);</script>"
} else {
out << "<script type='text/javascript'>_gaq.push(['_trackPageview']);</script>"
}
}
}

To use the tag, here is the line of code I added to the <head> of the layout.gsp…

<bc:googleAnalyticsWebflowUrl/>

This tag should be placed somewhere after the Google Analytics javascript that’s already been added to the site.

The code in my tag first checks to see if there’s a flowExecutionKey in the request. If there is a flowExecutionKey (meaning the page is part of a flow) the javascript added to the page will include the customized url value for Google Analytics to use to track the page. If the page is not part of a flow, the default javascript code is included on the page, and the url for the page is tracked normally by Google Analytics.

Quick notes about the attributes used in my tag code…

  • request, grailsApplication, controllerName and actionName are all variables available in the scope of a Grails tag library.
  • def appName = grailsApplication.metadata[‘app.name’] //This line of code grabs the metadata assigned to the app.name property in the application.properties file; this value is customizable.
  • ProgressData is a class defined in our application where we store the names of the steps in our flow. We use this data to track the users progress through the flow in order to display a progress bar on each page. Since this was already used in our flow, it was easy for me to use this same data to track the pages in Goole Analytics.

One last thing to note; since we’re adding the javascript to track page views via the tag, the line of code included in the original javascript should be removed, otherwise all the pages on the site will be tracked twice. Remove this line from the Google Analytics javascript…

_gaq.push(['_trackPageview']);

Now the Google Analytics report looks much cleaner with the revised urls and it’s easier to analyze the data.

Urls No Execution Key image

About the Author

Object Partners profile.

One thought on “Google Analytics Page Tracking in Grails Web Flow

Leave a Reply

Your email address will not be published.

Related Blog Posts
Natively Compiled Java on Google App Engine
Google App Engine is a platform-as-a-service product that is marketed as a way to get your applications into the cloud without necessarily knowing all of the infrastructure bits and pieces to do so. Google App […]
Building Better Data Visualization Experiences: Part 2 of 2
If you don't have a Ph.D. in data science, the raw data might be difficult to comprehend. This is where data visualization comes in.
Unleashing Feature Flags onto Kafka Consumers
Feature flags are a tool to strategically enable or disable functionality at runtime. They are often used to drive different user experiences but can also be useful in real-time data systems. In this post, we’ll […]
A security model for developers
Software security is more important than ever, but developing secure applications is more confusing than ever. TLS, mTLS, RBAC, SAML, OAUTH, OWASP, GDPR, SASL, RSA, JWT, cookie, attack vector, DDoS, firewall, VPN, security groups, exploit, […]