I have put together a page to display my Google Analytics information for my ASP.NET sites using some other help around the net and a little know-how.

I started by building this class, which I call GoogleAnalytics.cs:

using System;
using System.Collections.Generic;
using System.Web;
using System.Net;
using System.IO;
using System.Text;
using System.Xml;
using System.Collections.Specialized;
using System.Diagnostics;

/// 
/// Summary description for GoogleAnalytics
/// 
public class GoogleAnalytics
{
    public enum mode { ClientLogin, AuthSub }
    
    //used when you want to manage email/pass from within your app
    public static string getSessionTokenClientLogin(string email, string password)
    { 
        //Google analytics requires certain variables to be POSTed
        string postData = "Email=" + email + "&Passwd=" + password;

        //defined - should not channge much
        postData = postData + "&accountType=HOSTED_OR_GOOGLE" + "&service=analytics" + "&source=ACNSSite";
        
        ASCIIEncoding encoding = new ASCIIEncoding();
        byte[] data = encoding.GetBytes(postData);

        HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create("https://www.google.com/accounts/ClientLogin");
        myRequest.Method = "POST";
        myRequest.ContentType = "application/x-www-form-urlencoded";
        myRequest.ContentLength = data.Length;
        Stream newStream = myRequest.GetRequestStream();

        // Send the data.
        newStream.Write(data, 0, data.Length);
        newStream.Close();

        HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
        Stream responseBody = myResponse.GetResponseStream();

        Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
        StreamReader readStream = new StreamReader(responseBody, encode);

        //returned from Google Analytics API
        string response = readStream.ReadToEnd();

        //get the data we need
        string[] auth = response.Split(new string[] { "Auth=" }, StringSplitOptions.None);
        
        //return it (the authorization token)
        return auth[1];
    }

    //used when you have authenticated on Google (via AuthSub & query params) & have a temp token
    public static string getSessionTokenAuthSub(string tempToken)
    {
        string response = GArequestResponseHelper("https://www.google.com/accounts/AuthSubSessionToken", tempToken, mode.AuthSub);
        Debug.WriteLine("getting this far");
        Debug.WriteLine("perm token=" + response.Split('=')[1]);
        //temp (once off) token will have been exchanged for session token, return it
        return response.Split('=')[1];
    }

    public static NameValueCollection getAccountInfo(string sessionToken, mode mode)
    {
        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/accounts/default", sessionToken, mode);

        //response will contain an XML formatted string similar to
        //http://code.google.com/p/ga-api-http-samples/source/browse/trunk/src/v1/accountFeedResponse.xml

        //we need to convert it to proper XML for parsing
        XmlDocument accountinfoXML = new XmlDocument(); accountinfoXML.LoadXml(response);

        //each account/profile combo the current user is authorized for will an 'entry' element
        XmlNodeList entries = accountinfoXML.GetElementsByTagName("entry");

        NameValueCollection profiles = new NameValueCollection();
        for (int i = 0; i < entries.Count; i++)
        {
            //profile name, profile ID - profile ID is needed for ID what data you want from the API
            profiles.Add(entries.Item(i).ChildNodes[2].InnerText,entries.Item(i).ChildNodes[6].Attributes["value"].Value);
        }

        return profiles;
    }

    public static string getContentOverviewData(string sessionToken, string profileID, mode mode)
    {
        //we'll also want to pass in non hardcoded dates and report specifiers
        //month in format yyyy-mm-dd etc. 
        //At the moment we just getting pageview metric for our sites URLs
        //for the purposes of demostration

        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/data?ids=ga:" + profileID + "&dimensions=ga:pageTitle&metrics=ga:pageviews&sort=-ga:pageviews&start-date=" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd") + "&end-date=" + DateTime.Now.ToString("yyyy-MM-dd") + "&prettyprint=true&max-results=20", sessionToken, mode);

        //response will contain an XML formatted string similar to
        //http://code.google.com/p/ga-api-http-samples/source/browse/trunk/src/v1/dataFeedResponse.xml

        return response;
    }

    public static string getContentOverViewDataByTime(string sessionToken, string profileID, mode mode)
    {
        return "";
    }

    public static string getTrafficSourcesOverviewData(string sessionToken, string profileID, mode mode)
    {
        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/data?ids=ga:" + profileID + "&dimensions=ga:source&metrics=ga:pageviews&sort=-ga:pageviews&start-date=" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd") + "&end-date=" + DateTime.Now.ToString("yyyy-MM-dd") + "&prettyprint=true&max-results=10", sessionToken, mode);

        return response;
    }

    public static string getMapOverlayData(string sessionToken, string profileID, mode mode)
    {
        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/data?ids=ga:" + profileID + "&dimensions=ga:country&metrics=ga:pageviews&sort=-ga:pageviews&start-date=" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd") + "&end-date=" + DateTime.Now.ToString("yyyy-MM-dd") + "&prettyprint=true&max-results=100", sessionToken, mode);

        return response;
    }

    public static string getVisitsData(string sessionToken, string profileID, mode mode)
    {
        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/data?ids=ga:" + profileID + "&metrics=ga:visitors&start-date=" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd") + "&end-date=" + DateTime.Now.ToString("yyyy-MM-dd") + "&prettyprint=true&max-results=100", sessionToken, mode);

        return response;
    }

    public static string getPageViewsData(string sessionToken, string profileID, mode mode)
    {
        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/data?ids=ga:" + profileID + "&metrics=ga:pageviews&start-date=" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd") + "&end-date=" + DateTime.Now.ToString("yyyy-MM-dd") + "&prettyprint=true&max-results=100", sessionToken, mode);

        return response;
    }

    public static string getPagesPerVisitData(string sessionToken, string profileID, mode mode)
    {
        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/data?ids=ga:" + profileID + "&metrics=ga:uniquePageviews,ga:visits&start-date=" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd") + "&end-date=" + DateTime.Now.ToString("yyyy-MM-dd") + "&prettyprint=true&max-results=100", sessionToken, mode);

        return response;
    }

    public static string getBounceRateData(string sessionToken, string profileID, mode mode)
    {
        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/data?ids=ga:" + profileID + "&metrics=ga:bounces,ga:entrances&start-date=" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd") + "&end-date=" + DateTime.Now.ToString("yyyy-MM-dd") + "&prettyprint=true&max-results=100", sessionToken, mode);

        return response;
    }

    public static string getAvgTimeOnSiteData(string sessionToken, string profileID, mode mode)
    {
        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/data?ids=ga:" + profileID + "&metrics=ga:timeOnSite,ga:visits&start-date=" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd") + "&end-date=" + DateTime.Now.ToString("yyyy-MM-dd") + "&prettyprint=true&max-results=100", sessionToken, mode);

        return response;
    }

    public static string getNewVisitsData(string sessionToken, string profileID, mode mode)
    {
        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/data?ids=ga:" + profileID + "&metrics=ga:newVisits,ga:visits&start-date=" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd") + "&end-date=" + DateTime.Now.ToString("yyyy-MM-dd") + "&prettyprint=true&max-results=100", sessionToken, mode);

        return response;
    }

    public static string getVisitsPerDayData(string sessionToken, string profileID, mode mode)
    {
        string response = GArequestResponseHelper("https://www.google.com/analytics/feeds/data?ids=ga:" + profileID + "&dimensions=ga:day&metrics=ga:visits&start-date=" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd") + "&end-date=" + DateTime.Now.ToString("yyyy-MM-dd") + "&prettyprint=true&max-results=100", sessionToken, mode);

        return response;
    }

    public static string GArequestResponseHelper(string url, string token, mode mode)
    {
        HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(url);
        
        //will always be a token of some sort required in the header but the format
        //it is passed in will depend on what type of authorization is being used
        if (mode == mode.ClientLogin)
        { 
            myRequest.Headers.Add("Authorization: GoogleLogin auth=" + token);
        }
        else if (mode == mode.AuthSub)
        { 
            myRequest.Headers.Add("Authorization: AuthSub token=" + token);
        }

        //obviously you need some kind of try/catch here
        //but OK to bubble auth/connection failures up for demo
        HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
        Stream responseBody = myResponse.GetResponseStream();

        Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
        StreamReader readStream = new StreamReader(responseBody, encode);

        //return string itself (easier to work with)
        return readStream.ReadToEnd();
    }
}

I then created a page to display the data, you can see an example of this at http://www.mattgoodrich.com/Analytics.aspx. The markup is as follows:


    " rel="stylesheet" type="text/css" />
    
    
    
  


Google Analytics

Back to Admin

This is an overview of analytic data from Google Analytics from the past 30 days. If you would like to view the full reports visit Google Analytics.

Visits

Site Usage

Metric Value
Visits
Pageviews
Pages/Visit
Bounce Rate
Average Time on Site
New Visits

Map Overlay

Traffic Sources Overview

Content Overview

I use a very hack-ish method of injecting data into my javascript functions, there is no doubt a better way of doing this (AJAX), but I wrote this a good amount of time ago before I knew better.

Now for the meat and bones that really make all of this work together. Here is the code behind:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Configuration;
using System.Xml;
using System.Data;
using System.Globalization;

public partial class admin_Analytics : System.Web.UI.Page
{
    public string ChartData;
    public string MapOverlay;
    public int MapCount;
    public string VisitsData;

    protected void Page_Load(object sender, EventArgs e)
    {
        //resultsXML.Save(Server.MapPath("../") + "\\files\\test.xml");
        string token = GoogleAnalytics.getSessionTokenClientLogin(ConfigurationManager.AppSettings["AnalyticsLogin"], ConfigurationManager.AppSettings["AnalyticsPassword"]);
        Session["token"] = token;

        LoadVisits();
        LoadSiteUsage();
        LoadMapOverlay();
        LoadTrafficSourcesOverview();
        LoadContentOverview();
    }

    protected void LoadVisits()
    {
        string results = GoogleAnalytics.getVisitsPerDayData(Session["token"].ToString(), ConfigurationManager.AppSettings["AnalyticsProfileID"], GoogleAnalytics.mode.ClientLogin);
        //we need to convert it to proper XML for parsing
        XmlDocument resultsXML = new XmlDocument(); resultsXML.LoadXml(results);

        //each line/record return from the API will be contained in an 'entry' element
        XmlNodeList entries = resultsXML.GetElementsByTagName("entry");

        VisitsData += "data.addRows(" + entries.Count + ");";

        int i = 0;
        foreach (XmlNode node in entries)
        {
            DateTime time = DateTime.Now.AddDays(-31 + Convert.ToInt32(node.ChildNodes[4].Attributes["value"].Value));
            VisitsData += "data.setValue(" + i + ", 0, '" + time.ToShortDateString() + "');";
            VisitsData += "data.setValue(" + i + ", 1, " + node.ChildNodes[5].Attributes["value"].Value + ");";
            i++;
        }
    }

    protected void LoadSiteUsage()
    {
        string results = GoogleAnalytics.getVisitsData(Session["token"].ToString(), ConfigurationManager.AppSettings["AnalyticsProfileID"], GoogleAnalytics.mode.ClientLogin);
        //we need to convert it to proper XML for parsing
        XmlDocument resultsXML = new XmlDocument(); resultsXML.LoadXml(results);

        //each line/record return from the API will be contained in an 'entry' element
        XmlNodeList entries = resultsXML.GetElementsByTagName("entry");

        Literal1.Text = entries[0].ChildNodes[4].Attributes["value"].Value;

        results = GoogleAnalytics.getPageViewsData(Session["token"].ToString(), ConfigurationManager.AppSettings["AnalyticsProfileID"], GoogleAnalytics.mode.ClientLogin);
        resultsXML = new XmlDocument(); resultsXML.LoadXml(results);
        entries = resultsXML.GetElementsByTagName("entry");

        Literal2.Text = entries[0].ChildNodes[4].Attributes["value"].Value;

        results = GoogleAnalytics.getPagesPerVisitData(Session["token"].ToString(), ConfigurationManager.AppSettings["AnalyticsProfileID"], GoogleAnalytics.mode.ClientLogin);
        resultsXML = new XmlDocument(); resultsXML.LoadXml(results);
        entries = resultsXML.GetElementsByTagName("entry");

        Literal3.Text = (Convert.ToDouble(entries[0].ChildNodes[4].Attributes["value"].Value) / Convert.ToDouble(entries[0].ChildNodes[5].Attributes["value"].Value)).ToString();

        results = GoogleAnalytics.getBounceRateData(Session["token"].ToString(), ConfigurationManager.AppSettings["AnalyticsProfileID"], GoogleAnalytics.mode.ClientLogin);
        resultsXML = new XmlDocument(); resultsXML.LoadXml(results);
        entries = resultsXML.GetElementsByTagName("entry");

        Literal4.Text = (Convert.ToDouble(entries[0].ChildNodes[4].Attributes["value"].Value) / Convert.ToDouble(entries[0].ChildNodes[5].Attributes["value"].Value)).ToString("0.##%", CultureInfo.CurrentCulture);

        results = GoogleAnalytics.getAvgTimeOnSiteData(Session["token"].ToString(), ConfigurationManager.AppSettings["AnalyticsProfileID"], GoogleAnalytics.mode.ClientLogin);
        resultsXML = new XmlDocument(); resultsXML.LoadXml(results);
        entries = resultsXML.GetElementsByTagName("entry");

        TimeSpan t = TimeSpan.FromSeconds(Convert.ToDouble(entries[0].ChildNodes[4].Attributes["value"].Value) / Convert.ToDouble(entries[0].ChildNodes[5].Attributes["value"].Value));

        Literal5.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", t.Hours, t.Minutes, t.Seconds);

        results = GoogleAnalytics.getNewVisitsData(Session["token"].ToString(), ConfigurationManager.AppSettings["AnalyticsProfileID"], GoogleAnalytics.mode.ClientLogin);
        resultsXML = new XmlDocument(); resultsXML.LoadXml(results);
        entries = resultsXML.GetElementsByTagName("entry");

        Literal6.Text = (Convert.ToDouble(entries[0].ChildNodes[4].Attributes["value"].Value) / Convert.ToDouble(entries[0].ChildNodes[5].Attributes["value"].Value)).ToString("0.##%", CultureInfo.CurrentCulture);
    }

    protected void LoadMapOverlay()
    {
        string results = GoogleAnalytics.getMapOverlayData(Session["token"].ToString(), ConfigurationManager.AppSettings["AnalyticsProfileID"], GoogleAnalytics.mode.ClientLogin);
        //we need to convert it to proper XML for parsing
        XmlDocument resultsXML = new XmlDocument(); resultsXML.LoadXml(results);

        //each line/record return from the API will be contained in an 'entry' element
        XmlNodeList entries = resultsXML.GetElementsByTagName("entry");

        MapCount = entries.Count;

        int i = 0;
        foreach (XmlNode node in entries)
        {
            MapOverlay += "data.setValue(" + i + ", 0, '" + node.ChildNodes[4].Attributes["value"].Value + "');";
            MapOverlay += "data.setValue(" + i + ", 1, " + node.ChildNodes[5].Attributes["value"].Value + ");";
            i++;
        }
    }

    protected void LoadTrafficSourcesOverview()
    {
        string results = GoogleAnalytics.getTrafficSourcesOverviewData(Session["token"].ToString(), ConfigurationManager.AppSettings["AnalyticsProfileID"], GoogleAnalytics.mode.ClientLogin);
        //we need to convert it to proper XML for parsing
        XmlDocument resultsXML = new XmlDocument(); resultsXML.LoadXml(results);

        //each line/record return from the API will be contained in an 'entry' element
        XmlNodeList entries = resultsXML.GetElementsByTagName("entry");

        ChartData += "data.addRows(" + entries.Count + ");";

        int i = 0;
        foreach (XmlNode node in entries)
        {
            ChartData += "data.setValue(" + i + ", 0, '" + node.ChildNodes[4].Attributes["value"].Value + "');";
            ChartData += "data.setValue(" + i + ", 1, " + node.ChildNodes[5].Attributes["value"].Value + ");";
            i++;
        }
    }

    protected void LoadContentOverview()
    {
        string results = GoogleAnalytics.getContentOverviewData(Session["token"].ToString(), ConfigurationManager.AppSettings["AnalyticsProfileID"], GoogleAnalytics.mode.ClientLogin);
        //we need to convert it to proper XML for parsing
        XmlDocument resultsXML = new XmlDocument(); resultsXML.LoadXml(results);

        //each line/record return from the API will be contained in an 'entry' element
        XmlNodeList entries = resultsXML.GetElementsByTagName("entry");

        DataTable table;
        table = MakeContentOverviewTable();

        foreach (XmlNode node in entries)
        {
            DataRow row = table.NewRow();

            row["pageTitle"] = node.ChildNodes[4].Attributes["value"].Value;
            row["pageViews"] = node.ChildNodes[5].Attributes["value"].Value;

            table.Rows.Add(row);
        }

        GridView1.DataSource = table;
        GridView1.DataBind();
    }

    private DataTable MakeContentOverviewTable()
    {
        DataTable ContentOverview = new DataTable("ContentOverview");

        DataColumn idColumn = new DataColumn();
        idColumn.DataType = System.Type.GetType("System.Int32");
        idColumn.ColumnName = "id";
        idColumn.AutoIncrement = true;
        ContentOverview.Columns.Add(idColumn);

        DataColumn pageTitle = new DataColumn();
        pageTitle.DataType = System.Type.GetType("System.String");
        pageTitle.ColumnName = "pageTitle";
        ContentOverview.Columns.Add(pageTitle);

        DataColumn pageViews = new DataColumn();
        pageViews.DataType = System.Type.GetType("System.Int32");
        pageViews.ColumnName = "pageViews";
        ContentOverview.Columns.Add(pageViews);

        return ContentOverview;
    }
}

All you need to do at this point is make sure that you have the following lines in the Web.Config: