Monday, November 24, 2008

More Google Analytics in SAP Portal with jQuery

One of the challenges with SAP Portal and integrating Google Analytics is it's tendency to create a lot of links that pop content open in a new window. Since you don't have access to the code that creates these URLs it causes a wee bit of a headache when you look to determine what items are being clicked on in the KM, or where your users are linking out of the portal to certain other applications.

We can resolve some of this by using a javascript library to scrape the HTML page and insert some onclick events that will allow the items to be tracked.

How can we accomplish this?

There are two steps:

First, add access to your favorite javascript library inside the Google Analytics code. I've chosen jQuery, although you could easily use other libraries. You can do this through the ga-split-1.js file that was outlined earlier. Don't forget to change the name of the file if need be so it is not cached in users browsers.

var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "' type='text/javascript'%3E%3C/script%3E"));
document.write(unescape("%3Cscript src='' type='text/javascript'%3E%3C/script%3E"));

By pulling jQuery from Google, we're increasing our load time, since we won't have to wait on connections to the Portal. The risk is low, since it's Google. In addition, if jQuery isn't found, we just won't track certain types of links. We'd still get the key pack clicking information.

The second part is to actually use jQuery to track stuff. You might be able to use the jQuery GA plugin, but in my case, I decided to write my own javascript based upon the plugin to do the trick. I would keep this code in a separate file and load it after you've initialized the pageTracker within your PortalComponent:

function ga_decorateLink(u){
var trackingURL = '';
if(u.indexOf('://') == -1 && u.indexOf('mailto:') != 0){
// no protocol or mailto - internal link - check extension
var ext = u.split('.')[u.split('.').length - 1];
var exts = ['pdf','doc','xls','csv','jpg','gif', 'mp3','swf','txt','ppt','zip','gz','dmg','xml']
for(i = 0; i < exts.length; i++){
if(ext == exts[i]){
// Likely grabbing an item from KM, etc.
trackingURL = '/downloads/' + u;
} else {
if(u.indexOf('mailto:') == 0){
// mailto link - decorate
trackingURL = '/mailto/' + u.substring(7);
} else {
// complete URL - check domain
var regex = /([^:\/]+)*(?::\/\/)*([^:\/]+)(:[0-9]+)*\/?/i;
var linkparts = regex.exec(u);
var urlparts = regex.exec(location.href);
if(linkparts[2] != urlparts[2]) trackingURL = '/external/' + u; /*leaving the portal*/
return trackingURL;

// Since you've initialized pageTracker in each Portal page, we're skipping that here.
// just wait until the entire page loads
var u = $(this).attr('href');

if(typeof(u) != 'undefined'){
var newLink = decorateLink(u);

If you're using the defualt framework, be aware that you will not be able to track each and every link. Javascript cannot dive into iframes on the page. Since it can't do that, you'll be unable to track each and every link, unless you can use embedded for that particular iView which will eliminate the iframes.

Some fair warning here. This is from memory. I am no longer working with SAP Portal, so there is a good chance I've forgotten something here. However, it did work on my last day working with least the version at that gig. If you run into problems, please fix them and share them. Don't hold onto it. Share it with the rest of the SAP community, post it on your blog, or submit it to SDN for inclusion in their hosted materials. At the very least, post a solution in the SDN forums so that others can use this. When you get it working, it's pretty darned cool!


Robert said...

Hi Mike,

just found your blog via a tweet from @oliver. Really great information!
Have you posted this also on SCN?
I think it's very valuable and would increase the quality in the portal blogs area ;-)

Best regards,
Robert Briese

Mike said...

Hi Robert,

I am not aware of SCN. SDN I know of, but not SCN. I've no problem with this being linked to elsewhere, but I don't know if this code is bug free. It works as I had it working 2 weeks ago. However, I don't know if there's something wrong with the syntax, or an edge case I've forgotten about since I don't have access to SAP Portal.

I'm not currently working in SAP Portal as I left that gig after 6 months. I'm back to doing enterprise Java consulting right now. I hope that this can be of help for those who are still working with SAP's Portal product. Unless SAP Portal becomes more flexible, it will lose market share to MOSS, JBoss, Liferay and other least around here.