Showing posts with label Google Analytics. Show all posts
Showing posts with label Google Analytics. Show all posts

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 + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
document.write(unescape("%3Cscript src='http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js' 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;
break;
}
}
} 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
$(document).ready(function(){
$('a').each(function(){
var u = $(this).attr('href');

if(typeof(u) != 'undefined'){
var newLink = decorateLink(u);
if(newLink.length){
$(this).click(function(){
$.pageTracker._trackPageview(newLink);
});
}
}
});
});


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 Portal...at 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!

Saturday, July 26, 2008

Updating Javascript in SAP Portal

Quick reminder to those of you who've followed my posts on Google Analytics.

Be sure that if you're updating a Javascript file that you take the time to update the version of the file. SAP Portal does this using a query string like construct after the javascript file for its OOTB components.

You can do a similar construct for your files by simply embedding a version into the file name. Following the previous GA example, you can simply update the file name to be ga-split-2.0.1.js

Of course, the next step is to update the PortalComponent to pull in the correct version of the file.

So why do you need to do this? Depending upon how your Portal and Load Balancers are setup with caching and expires headers, you won't push the correct version of the javascript file to the browser unless you update the file name! Why? It's common practice to set Expires headers in the far future and set the browser to cache the javascript file. If your setup is doing that, then any changes you make the the original JS file will not be pulled in unless your users happened to clear their browser cache. Since the chance of your entire user community pulling that off is miniscule, the only way to force them to get the new version of the file is to update the file name!

Also, be sure you head over and look at what Spyvee did to inspire these posts over at NetweaverCentral.

Thursday, July 17, 2008

Enhanced Google Analytics in SAP Portal

If you happened to follow my post on integrating Google Analytics with SAP Portal, and attempted to implement it, you may have found some challenges with the reports. More specifically:
  • If you're using the Light Framework (or derivation), all of your URLs are unreadable. They don't describe what is going on in the page since the Portal uses GUIDs as a URL parameter to gather the appropriate page.
  • If you're using the Default Framework (or derivation), you only show hits on your entry point. Which is great for gathering browser information, but not so much for following user activity.
  • In order to resolve this problem, you decide to add the Analytics iView to other pages in your Portal. Now all of your URLs are really unreadable. In fact, you will find that you receive multiple URLs for the same page, where the only difference is the windowID in the query string. This makes the data flat out unusable.
So, what to do?

There is a single fix that resolves both issues. The fix involves asking Portal where in the Navigation Tree you are. First, add in some imports to your code:

import com.sapportals.portal.navigation.INavigationNode;
import com.sapportals.portal.navigation.NavigationEventsHelperService;
import com.sapportals.portal.prt.runtime.PortalRuntime;
import com.sapportals.portal.prt.pom.IEvent;


In order to use these, you'll need to get the following JARs and import them into your project:
  • com.sap.portal.navigation.api_service_api.jar
  • com.sap.portal.navigation.helperservice_api.jar
  • com.sap.portal.navigation.helperservice_core.jar
One of the methods you can override in an AbstractPortalComponent is doOnNodeReady(). This method is called once the PortalNode has been constructed. At this point, the node can ask the Portal for information. The method is implemented as follows:

    
protected void doOnNodeReady(IPortalComponentRequest request,IEvent arg1) {
// Get the service to access the Navigation information
NavigationEventsHelperService helperService =(NavigationEventsHelperService) PortalRuntime.getRuntimeResources().getService("com.sap.portal.navigation.helperservice.navigation_events_helper");
// Get your current location in the navigation tree
INavigationNode navTargetNode = helperService.getCurrentLaunchNavNode(request);
StringBuffer fullPath = new StringBuffer(navTargetNode.getTitle(Locale.ENGLISH));
// After stashing the title of the node, get the node's parent and loop
// until you've reached the top node. Stash each parent's name and build
// a navigation "path" for use later.
INavigationNode aParent = helperService.getParentNode(navTargetNode, request);
while (aParent != null && !aParent.getTitle(Locale.ENGLISH).equals("")) {
fullPath.insert(0, aParent.getTitle(Locale.ENGLISH) + "/");
aParent = helperService.getParentNode(aParent, request);
}
// store the path in a member variable that can be used inside doContent()
pageTitle = fullPath.toString();
}

Once you've created this path, you can then use it to track the page properly. Inside ga-split-2.js, you should remove the final line which calls pageTracker._trackPageview() Instead, you'll create a set of response.write() calls to use the pageTitle object and write a new snippet of code on each specific page.

The end of doContent will look as follows:


response.include(request, googleAnalyticsDataResource2);
response.write("<script type=\"text/javascript\">\n");
response.write("pageTracker._trackPageview(\""+ pageTitle +"\");\n");
response.write("</script>");

response.setContentType(PortalComponentContentType.HTML);


How to use the enhancements:

If you're in the light framework, it will just work. You can keep the code at the framework level and it will work on every page in the portal. If you're in the default framework, you'll need to add the code to each page that you want to track. You may want to remove the code from the framework and just track pages. The resulting reports will be far more readable and much better for your business users and portal sponsors who would likely be consuming the data (and pretty graphs) that Google Analytics provides.

Wednesday, June 18, 2008

SAP Portal and Google Analytics

Some folks over at Spyvee created a document on how to integrate Google Analytics with SAP Portal. It's a very good document but, I didn't care for the fact that the code would not be entered in a standard place for javascript.

Essentially SAP takes a lot of ownership over how objects are inserted into the portal. Ideally you'd want to place the Google Anayltics code right above the tag in your page. Portal doesn't quite let you do that. At least not with any ease.

The next best place for javascript code is at the bottom of the head....at least in SAP Portal. Why? Because you can easily place it there using an AbstractPortalComponent.

Here's some modified steps to Spyvee's document that will allow you to insert Google Analytics into your Portal Framework and track a whole lot of clicks.

Netweaver Portal Integration:

When you get to this part, create a PAR with an AbstractPortalComponent. Create something like this:

package com.corp.portal.tools;

import com.sapportals.portal.prt.component.*;
import com.sapportals.portal.prt.resource.IResource;

public class GoogleAnalytics extends AbstractPortalComponent {

public void doContent(IPortalComponentRequest request, IPortalComponentResponse response) {
IResource googleAnalyticsDataResource = request.getResource(IResource.SCRIPT, "scripts/ga-split-1.js");
response.include(request, googleAnalyticsDataResource);
IResource googleAnalyticsDataResource2 = request.getResource(IResource.SCRIPT, "scripts/ga-split-2.js");
response.include(request, googleAnalyticsDataResource2);
response.setContentType(PortalComponentContentType.HTML);
}
}


What this code will do is pull two scripts that you will create in the scripts directory of the portal application. These two scripts will be the two parts of the ga.js code you grabbed from Google. The code is split into two pieces surrounded by script tags. So creating the following script files will do the trick:

ga-split-1.js:

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


ga-split-2.js:
var pageTracker = _gat._getTracker("UA-XXXXXX-3");
pageTracker._initData();
pageTracker._trackPageview();


Obviously, don't copy this straight as you'll want your personalized tracking code instead of XXXXXXX :)

Once you've uploaded and created an iView, stash the iView at the bottom of your framework. I'm assuming you needed to customize it and aren't using the out of the box SAP framework. If you stash the iView at the bottom, and it's working, you'll see two script tags in the head to your two scripts, and you'll find a script between them calling the google-analytics.com/ga.js script.

Eventually Google will pick up that it's working and you'll begin to track your clicks. Just beware that if you're behind a firewall, you will probably get some strange results as to where your clicks are being routed depending upon your network topology. I've got requests in Ohio showing up as Chicago, which is where the google analytics call is being routed.

ShareThis