Tripleodeon

Mobile Analytics With Python, Django, ASP.NET, Java, and node.js

A few weeks ago, the PercentMobile team came to me to see if I could help write some new libraries for them. Contemporary web and mobile web sites are written on a vast array of different platforms… and obviously the more that PercentMobile supports, the better.

Something I love about programming is that there are so many languages to choose from – why restrict yourself to learning or becoming an expert at one when the same problems are also being solved in other, sometimes better, ways? Each language or platform has strengths and weaknesses of course. But I believe that understanding the differences – and more often, the similarities – makes one a better programmer.

So, generous polyglot that I am, I took the challenge, and plunged in.

(Sign up for the free PercentMobile service to get the libraries described in this post.)

Python & Django

I love Python – its readability, its libraries, and its overall philosophies. In a web server environment, Python can be used in a fairly raw way, behind a generic Web Service Gateway Interface (WSGI), but there are also a number of powerful web application frameworks using the language – most notably Django. PercentMobile want to provide painless Django support, but also to make sure that other Python server environments were not precluded.

percentmobile.py is the single file that provides everything you need.

If you are running code in a WSGI environment, you will have a handle to the WSGI environment. This is normally called environ by convention, and is passed in to your application via your top-level WSGI callable. To make the PercentMobile tracking code work, you need only make one call to the percentmobile.tracker_cookie_insert function. It returns two values: the cookie that you’ll need to set in the HTTP response headers, and the HTML that you should insert into your page.

Say, for example, you had a very simple WSGI app. This responds to requests with an HTTP 200 status code, a single header and some simple HTML:

def my_app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type','text/html')]
    start_response(status, response_headers)
    return ["Hello world"]

To add PercentMobile tracking to this code, you need to firstly import the tracker library of course, and then call the tracker_cookie_insert function:

import percentmobile
cookie, insert = percentmobile.tracker_cookie_insert(environ, '1234555')

(Of course you should replace the final string with your own site ID!)

The cookie return value is actually a dictionary of the different parts needed to construct its string serialization. This will allow you to splice together multiple cookies, or alter the expiry time, path scope and so on. To convert the dictionary to a string, and to get the Set-Cookie header sent back in the request headers, the following code will suffice:

cookie = "%s=%s; expires=%s; path=%s" % (
    cookie['name'],
    cookie['value'],
    cookie['expires'],
    cookie['path']
)
response_headers = [('Content-type','text/html'), ('Set-Cookie', cookie)]

Finally, you need to make sure the HTML fragment, in the insert variable, gets placed in the HTML response:

return ["<html><body>Hello world %s</body></html>" % insert]

And that’s a wrap. The whole, PercentMobile-tracked WSGI application looks like this:

def my_app(environ, start_response):
    cookie, insert = percentmobile.tracker_cookie_insert(environ, '1234555')
    cookie = "%s=%s; expires=%s; path=%s" % (
        cookie['name'],
        cookie['value'],
        cookie['expires'],
        cookie['path']
    )
    status = '200 OK'
    response_headers = [('Content-type','text/html'), ('Set-Cookie', cookie)]
    start_response(status, response_headers)
    return ["<html><body>Hello world %s</body></html>" % insert]

Pretty easy, huh? Well, not as easy as tracking an app if you’re using the amazing Django framework! Contained in the same percentmobile.py file is a class that can be used as Django middleware. It uses the same underlying function as the WSGI implementation, but also takes care of the headers and insertion for you.

Assuming you’ve placed the library file in your Python or Django path, you simply need to add two lines of code in the settings file. Firstly add the percentmobile.PercentMobileDjangoMiddleware class to your list of middleware:

MIDDLEWARE_CLASSES = (
    ...
    'percentmobile.PercentMobileDjangoMiddleware'
)

And secondly, add your PercentMobile site ID to the settings file too:

PERCENTMOBILE_SITE_ID = '1234555'

Um… that’s it. The middleware will intercept the request, figure out the cookie that will need to be sent in the response, create the insertion code, and place it just before </body> in the response. You’re golden. I love Django.

ASP.NET: C# & VB.NET

Switching over to another world altogether, let’s take a quick look at the ASP.NET implementation of the tracking code. One of the great things about .NET is that you can choose between all sorts of different languages to write your applications and pages in. I decided to write the tracking library in C#, but you can use it declaratively in your page code, or programmatically from C#, VB.NET, or any other supported language.

The library is implemented as a User Control – that is, as a .ascx file. You need to download and add PercentMobile.ascx to your web application project.

To embed the tracking logic into a page (or probably preferably, a master page), you simply register the user control as residing in that file:

<%@ Register TagPrefix="pm" TagName="Tracker" Src="~/PercentMobile.ascx" %>

And then embed the control straight into the .aspx file contents, wherever you want it to be:

<pm:Tracker runat="server" SiteId="1234555" />

So a simple, tracked .aspx file might look something like this:

<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Register TagPrefix="pm" TagName="Tracker" Src="~/PercentMobile.ascx" %>
<!DOCTYPE html>
<html>
    <head><title>Hello World</title></head>
    <body>
        <form id="form1" runat="server">
            <div>Hello World</div>
            <pm:Tracker runat="server" SiteId="1234555" />
        </form>
    </body>
</html>

To be honest, this is so simple that I would expect most people to use the control declaratively. But if, for some reason, the control needs to be inserted programmatically, that’s pretty easy too. You need to use the Reference directive, instead of Register, at the top of the file, but otherwise it’s not much harder. Here, we’re using VB.NET to programmatically achieve exactly the same result as above:

<%@ Page Language="VB" AutoEventWireup="true" %><%@ Reference Control="~/PercentMobile.ascx" %>

<script runat="server">
    Private tracker As PercentMobile.Tracker
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
        tracker = CType(LoadControl("~/PercentMobile.ascx"), PercentMobile.Tracker)
        tracker.siteId = "1234555"
        form1.Controls.Add(tracker)
    End Sub
</script>
<!DOCTYPE html>
<html>
    <head><title>Hello World</title></head>
    <body>
        <form id="form1" runat="server">
            <div>Hello World</div>
        </form>
    </body>
</html>

(It should be fairly straightforward to see how to do this in other .NET languages – PercentMobile includes some examples in their install instructions.)

Java

Onwards. Let’s take a look at the tracking code for Java. There are numerous ways in which Java can be used for web or application server environments. To keep things simple, I decided that supporting JSP was more or less the most familiar and reusable approach.

JSP doesn’t enjoy the rich page event model that I was able to use in ASP.NET to intercept headers, write cookies, and insert HTML, all with one include. <jsp:include> is OK for adding the HTML snippets, but wouldn’t let me access the HTTP headers. <jsp:forward> does, but would only work if you weren’t planning to emit any HTML of your own after the tracking code – something of a radical assumption.

So I settled for an approach where an include directive creates an instance of an inner PercentMobile class defined within the JSP class. To cut a long story short, this means you merely add a reference to the library file at the top of the JSP file:

<%@ include file="percentmobile.jsp" %>

And then call the track method on that instance, somewhere within the page:

<%percentMobile.track("1234555");%>

The included JSP file takes care of instantiating the percentMobile object and giving it references to the request and response stream. This means it can read and write cookies, and later emit HTML. Your tracked Hello World in Java then? It’s as simple as this:

<%@ include file="percentmobile.jsp" %>
 <html>
  <body>
    Hello World
    <%percentMobile.track("1234555");%>
  </body>
</html>

node.js

OK, OK. Python, ASP.NET, Java. No big deal, right? That’s all so 2003 or so, right?

Well, there’s an alternative future for web server technologies. It’s one that’s blazingly fast, lightweight, event-driven, and… where you write your server logic in Javascript.

node.js is one of the most exciting things I’ve seen for a long time, and I know I’m not alone. Fresh, fashionable, and somewhat unproven, admittedly, it’s had a lot of gushing coverage. But since it turns the web server model (almost literally) inside out, I do believe there’s something important going on.

Would it be possible to write a web app with node.js and still have it tracked by PercentMobile? My challenge.

I decided to rely on Connect, a middleware framework for node.js, which, if you are writing web applications, provides a whole host of other helpful web logic. Using Connect to create a simple node.js app is extremely easy:

var Connect = require('connect');
Connect.createServer(
  function (req, res, next) {
    res.simpleBody(200,
      "<html><body>Hello World" +
      "</body></html>",
      {
        "Content-Type": "text/html"
      }
    );
  }
).listen(88);

To add PercentMobile tracking to this application firstly requires you to pull in the PercentMobile module:

var PercentMobile = require('./percentmobile');

(Where the percentmobile.js file has been placed in your node.js environment or in the common modules location.)

The module needs to be initialized as a piece of Connect middleware in the createServer function:

PercentMobile.init('1234555')

There are then two module functions, cookie and html, which both take a reference to the response object, and which return the cookie string and HTML to insert, respectively. These can be used in Connect’s simpleBody function, for example, meaning that our tracked application is as simple as this:

var Connect = require('connect');
var PercentMobile = require('./percentmobile');
Connect.createServer(
  PercentMobile.init('1234555'),
  function (req, res, next) {
    res.simpleBody(200,
      "<html><body>Hello World" +
        PercentMobile.html(res) +
      "</body></html>",
      {
        "Content-Type": "text/html",
        "Set-Cookie": PercentMobile.cookie(res)
      }
    );
  }
).listen(88);

That’s a wrap

So that’s it. A whistle-stop tour of the new languages and frameworks supported by PercentMobile. I’d love to hear your feedback on how easy (or hard!) these new APIs are to use.

And, oh… who will be the first to build a mobile web app on node.js? 🙂