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:

  1. import com.sapportals.portal.navigation.INavigationNode;
  2. import com.sapportals.portal.navigation.NavigationEventsHelperService;
  3. import com.sapportals.portal.prt.runtime.PortalRuntime;
  4. import com.sapportals.portal.prt.pom.IEvent;
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:

  1. protected void doOnNodeReady(IPortalComponentRequest request,IEvent arg1) {
  2. // Get the service to access the Navigation information
  3. NavigationEventsHelperService helperService =(NavigationEventsHelperService) PortalRuntime.getRuntimeResources().getService("com.sap.portal.navigation.helperservice.navigation_events_helper");
  4. // Get your current location in the navigation tree
  5. INavigationNode navTargetNode = helperService.getCurrentLaunchNavNode(request);
  6. StringBuffer fullPath = new StringBuffer(navTargetNode.getTitle(Locale.ENGLISH));
  7. // After stashing the title of the node, get the node's parent and loop
  8. // until you've reached the top node. Stash each parent's name and build
  9. // a navigation "path" for use later.
  10. INavigationNode aParent = helperService.getParentNode(navTargetNode, request);
  11. while (aParent != null && !aParent.getTitle(Locale.ENGLISH).equals("")) {
  12. fullPath.insert(0, aParent.getTitle(Locale.ENGLISH) + "/");
  13. aParent = helperService.getParentNode(aParent, request);
  14. }
  15. // store the path in a member variable that can be used inside doContent()
  16. pageTitle = fullPath.toString();
  17. }
    
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.

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.