I’m a big fan of wordpress and really like the Google Analyticator plugin. It provides a dashboard widget that summarizes your analytics stats. I was working on a project that had a relatively sparse admin dashboard and figured I would provide a similar view of analytics stats. The main difference is that the project I was working on was an asp.net mvc3 project.
I searched for some analytics api examples for asp.net and didn’t really find much. So hopefully this will help someone who is looking to consume gdata apis from .net. All of the code is available on github for your viewing pleasure.
What does it look like?
Authenticating with Google Data Api
Authenticating with Google is pretty simple. Google supports a variety of authentication methods including OAuth2. I’m not entirely sure why, but I chose to go with their AuthSub method of authentication. Basically, you redirect the user to a specific Google url, they authorize your application and are returned to your application with a token. You can then use that token for one-time operation or convert the token to a long lasting token that can be used repeatedly.
The code I use to authenticate looks like:
public ActionResult Auth() | |
{ | |
const string scope = "https://www.google.com/analytics/feeds/"; | |
var next = Url.FullPath("~/home/authresponse"); | |
var url = AuthSubUtil.getRequestUrl(next, scope, false, true); | |
return Redirect(url); | |
} | |
public ActionResult AuthResponse(string token) | |
{ | |
var sessionToken = AuthSubUtil.exchangeForSessionToken(token, null); | |
Settings settings; | |
using (RavenSession.Advanced.DocumentStore.DisableAggressiveCaching()) | |
{ | |
settings = RavenSession.Load<Settings>(Settings.DefaultId); | |
} | |
if (settings == null) | |
settings = new Settings | |
{ | |
Id = Settings.DefaultId | |
}; | |
settings.SessionToken = sessionToken; | |
RavenSession.Store(settings); | |
return RedirectToAction("Config"); | |
} |
I store the long lasting token in an embedded instance of RavenDb. It’s a quick & super easy way to store things like that.
Querying Analytics
Now that you have a token from the user, you can query analytics to get data for any site that the user has access to. Google sites have a unique id associated with them, that Google calls TableId. You need to specify this value with any analytic data query. In order to get a list of available sites, you’ll need to query the account feed:
var authFactory = new GAuthSubRequestFactory("analytics", ApplicationName) | |
{ | |
Token = settings.SessionToken | |
}; | |
var analytics = new AnalyticsService(authFactory.ApplicationName) { RequestFactory = authFactory }; | |
foreach (AccountEntry entry in analytics.Query(new AccountQuery()).Entries) | |
{ | |
var account = entry.Properties.First(x => x.Name == "ga:accountName").Value; | |
if (!model.Sites.ContainsKey(account)) | |
model.Sites.Add(account, new Dictionary<string, string>()); | |
model.Sites[account].Add(entry.ProfileId.Value, entry.Title.Text); | |
} |
With that snippet, I organize the sites based on their associated account.
After choosing a specific site to work with, you can query information like total page views, average amount of time spent on the site, etc. The data feed explorer is quite handy in exploring the type of data that Analytics will return. For example, the following query will get a number of general stats across all pages:
var siteUsage = new DataQuery(settings.SiteId, from, to) | |
{ | |
Metrics = "ga:visits,ga:pageviews,ga:percentNewVisits,ga:avgTimeOnSite,ga:entranceBounceRate,ga:exitRate,ga:pageviewsPerVisit,ga:avgPageLoadTime" | |
}; | |
var siteUsageResult = (DataEntry)analytics.Query(siteUsage).Entries.FirstOrDefault(); | |
if (siteUsageResult != null) | |
{ | |
foreach (var metric in siteUsageResult.Metrics) | |
{ | |
switch (metric.Name) | |
{ | |
case "ga:visits": | |
model.TotalVisits = metric.IntegerValue; | |
break; | |
case "ga:pageviews": | |
model.TotalPageViews = metric.IntegerValue; | |
break; | |
case "ga:percentNewVisits": | |
model.PercentNewVisits = metric.FloatValue; | |
break; | |
case "ga:avgTimeOnSite": | |
model.AverageTimeOnSite = TimeSpan.FromSeconds(metric.FloatValue); | |
break; | |
case "ga:entranceBounceRate": | |
model.EntranceBounceRate = metric.FloatValue; | |
break; | |
case "ga:exitRate": | |
model.PercentExitRate = metric.FloatValue; | |
break; | |
case "ga:pageviewsPerVisit": | |
model.PageviewsPerVisit = metric.FloatValue; | |
break; | |
case "ga:avgPageLoadTime": | |
model.AveragePageLoadTime = TimeSpan.FromSeconds(metric.FloatValue); | |
break; | |
} | |
} | |
} |
Similarly, you can add dimensions to your query. Dimensions allow you to group the metrics data, similar to sql group by. The following query will get a list of pages sorted by most page views:
var topPages = new DataQuery(settings.SiteId, from, to) | |
{ | |
Metrics = "ga:pageviews", | |
Dimensions = "ga:pagePath,ga:pageTitle", | |
Sort = "-ga:pageviews", | |
NumberToRetrieve = 20 | |
}; | |
foreach (DataEntry entry in analytics.Query(topPages).Entries) | |
{ | |
var value = entry.Metrics.First().IntegerValue; | |
var url = entry.Dimensions.Single(x => x.Name == "ga:pagePath").Value.ToLowerInvariant(); | |
var title = entry.Dimensions.Single(x => x.Name == "ga:pageTitle").Value; | |
if (!model.PageViews.ContainsKey(url)) | |
model.PageViews.Add(url, 0); | |
model.PageViews[url] += value; | |
if (!model.PageTitles.ContainsKey(url)) | |
model.PageTitles.Add(url, title); | |
} |
The UI side of things
The graph is generated using the jquery sparkline plugin. While not as sexy as the official analytics graphs, it works for a quick view. Everything else on the page is styled with twitter bootstrap, with a few minor tweaks.
Conclusion
That’s about it. Have a look at the complete project to get a full understanding of how I used the analytics api to build an asp.net mvc widget that summarizes website analytics.