Click here to Skip to main content
13,298,481 members (42,724 online)
Click here to Skip to main content
Add your own
alternative version


40 bookmarked
Posted 2 Nov 2010

Retrieve Google Analytics Statistics Using .NET

, 5 Nov 2010
Rate this:
Please Sign up or sign in to vote.
This article provides a class library that can help programmers to get Google analytics data using .NET


This article provides a class library that can help programmers to get Google analytics data using .NET. The data which is returned is of IEnumberable class. So it can be bound to any bindable control to be viewed by the user.

The attached file contains the GAConnect DLL project along with a Winforms and Website project which you can use to retrieve your Google Analytics data.




I recently launched my website and wanted to show some statistical information (e.g. pages with most views) to the user. Well, I went for the best out there: Google Analytics. The last step was to be able to connect to Google Analytics and get the data from there and show it to the user. After searching for a while, I found out that Google has changed the way it handles Google Analytics requests and unfortunately, none of the code samples worked correctly. The best thing I could find was a great blog post at (although it didn't work either). Major parts of my code have been borrowed from his sample. To be able to use Google Analytics Data Export API, you'd have to get the corresponding tableId to your Analytics account. So, just knowing your trackingId will not do the trick. So I have created a DLL for .NET developers to connect to Google Analytics more easily. It makes it easier to perform the required 3 steps (Authentication, Account Query and Profile/Report Query) to be able to retrieve your data from Google Analytics. In the following chapters, I will explain both how to use this DLL to connect to Google Analytics and also how these steps are carried out in the GAConnect DLL itself.

Using the Code

To use the code, you have to add a reference to GAConnect.dll.

  1. Initialize and Authenticate: Create a new object of type GADataFetcher. Pass in your email address and password as the parameters. This object will carry out all the necessary steps for you to be able to get the data from Google:

    var gaDataFetcher = new GADataFetcher(txtEmail.Text, txtPassword.Text); 

    The constructor tries to authenticate the user with the given credentials. If the authentication fails, it will throw an exception:

    this.Email = email;
    this.Password = password;
        BaseData.authenticationKey = AuthenticationKey;

    As you can see, the authentication is handled by Authenticate method. The authentication URL and authentication post for Google are:

    private const string AuthenticationUrl =
    string AuthenticationPost =
               this.Email, this.Password);

    The Authenticate URL makes a HTTP POST request which checks if the result has an "Auth=" in it. If so, the user is authenticated and the authentication key is saved into a string variable for further requests.


  2. Account Query: The GAConnect DLL has a couple of classes for returning data. The first one is GAProfile with the following definition:
    public class GAProfile
          public string ID { get; set; }
          public DateTime Updated { get; set; }
          public string AccountID { get; set; }
          public string AccountName { get; set; }
          public string ProfileID { get; set; }
          public string WebPropertyID { get; set; }
          public string Currency { get; set; }
          public string TimeZone { get; set; }
          public string TableID { get; set; }
          public string Title { get; set; }

    Now we're ready to retrieve our account's profiles from Google. It's done by calling the following method:

    IEnumerable<GAProfile> profiles = gaDataFetcher.GetUserProfiles();   

    The profiles object now contains everything we need to get the real data from Google Analytics, including the TableIds associated with our profiles.


    The GetUserProfiles calls the GetProfilesData method of the BaseClass. It basically sends an HTTP Get Request to "". It also adds the authentication key to the request header. Otherwise, we get a Request Forbidden result. After getting the result (the user profiles) in an XML variable, the GetUserProfiles method calls GetProfiles. This is where our XML result will be mapped to an IEnumberable<GAProfile> object. The parsing/mapping is done by using lambda expressions and adding appropriate namespaces:

    static IEnumerable<GAProfile> GetProfiles<T>(XDocument xml)
            where T : GAProfile, new()
                XNamespace dxp = xml.Root.GetNamespaceOfPrefix("dxp");
                XNamespace dns = xml.Root.GetDefaultNamespace();
                IEnumerable<GAProfile> profiles = null;
                profiles = xml.Root.Descendants(dns + "entry").Select(f => new GAProfile
                    AccountID = f.Elements(dxp + "property").Where
    		( x => x.Attribute("name").Value==
                    AccountName = f.Elements(dxp + "property").Where
    		(x => x.Attribute("name").Value ==
                    ProfileID = f.Elements(dxp + "property").Where
    		(x => x.Attribute("name").Value ==
                    WebPropertyID = f.Elements(dxp + "property").Where
    		(x => x.Attribute("name").Value ==
                    Currency = f.Elements(dxp + "property").Where
    		(x => x.Attribute("name").Value ==
                    TimeZone = f.Elements(dxp + "property").Where
    		(x => x.Attribute("name").Value ==
                    TableID = f.Element(dxp + "tableId").Value,
                    Updated = DateTime.Parse(f.Element(dns + "updated").Value),
                    ID = f.Element(dns + "id").Value,
                    Title = f.Element(dns + "title").Value
                return profiles;
  3. Profile/Report Query: The second class I mentioned before is GAData:
    public class GAData
            public int Pageviews { get; set; }
            public int Bounces { get; set; }
            public int Entrances { get; set; }
            public int Exits { get; set; }
            public int NewVisits { get; set; }
            public double TimeOnPage { get; set; }
            public double TimeOnSite { get; set; }
            public int Visitors { get; set; }
            public int Visits { get; set; }
            public int UniquePageviews { get; set; }
            public string ExitPagePath { get; set; }
            public string LandingPagePath { get; set; }
            public string NextPagePath { get; set; }
            public string PagePath { get; set; }
            public string PageTitle { get; set; }
            public string PreviousPagePath { get; set; }
            public string SecondPagePath { get; set; }
            public string Browser { get; set; }
            public string BrowserVersion { get; set; }
            public string City { get; set; }
            public string ConnectionSpeed { get; set; }
            public string Country { get; set; }
            public string Date { get; set; }
            public string DaysSinceLastVisit { get; set; }
            public string Day { get; set; }
            public string FlashVersion { get; set; }
            public string Hostname { get; set; }
            public string IsMobile { get; set; }
            public string Hour { get; set; }
            public string JavaEnabled { get; set; }
            public string Language { get; set; }
            public string Latitude { get; set; }
            public string Longitude { get; set; }
            public string Month { get; set; }
            public string NetworkDomain { get; set; }
            public string NetworkLocation { get; set; }
            public string OperatingSystem { get; set; }
            public string OperatingSystemVersion { get; set; }
            public string PageDepth { get; set; }
            public string Region { get; set; }
            public string ScreenColors { get; set; }
            public string ScreenResolution { get; set; }
            public string SubContinent { get; set; }
            public string UserDefinedValue { get; set; }
            public int VisitCount { get; set; }
            public int VisitLength { get; set; }
            public string VisitorType { get; set; }
            public int Week { get; set; }
            public int Year { get; set; }
            public string Source { get; set; }

    The GAData objects contain the real statistics about our pages. To set the dimensions and metrics that we want to retrieve, two enums are defined:

    public enum Dimension
    public enum Metric

    To get the final results, first define what dimensions/metrics you're interested in and then call the GetAnalytics method. The GetAnalytics method's definition is as follows:

    public IEnumerable<GAData> GetAnalytics(string tableID, DateTime from,
    	DateTime to, int max,
             List<Dimension> dimensions, List<Metric> metrics,
    	Metric sort, SortDirection order)

    tableID can be retrieved from the previous section. notice that the tableID shouldn't contain "ga:" and maxNumber is the maximum number of returned GAData Items. For example, if you want to get the statistics for the last 30 days, you should do something like:

    var dimensions = new List<Dimension>();
    var metrics = new List<Metric>();
    var fromDate=DateTime.Now.AddDays(-30);
    var toDate=DateTime.Now;
    IEnumerable<GAData> data = gaDataFetcher.GetAnalytics
    	(myTableId, fromDate, toDate, 10,
           	dimensions, metrics, metrics[0], GAConnect.SortDirection.Descending);

    An important thing to note here is that not all dimension/metric combinations are allowed. If you provide an incorrect dimension/metric combination, you'll get Http 400 (Bad Request) exception. To view the valid combinations, check out this link.
    Now, what happens behind the scenes when you call GetAnalytics method, is that it calls the GetBaseData method:

    public static IEnumerable<BaseData> GetBaseData
    	(string tableID, IEnumerable<Dimension> dimensions,
          	IEnumerable<Metric> metrics, DateTime from, DateTime to,
    	Metric sort, SortDirection direction, int maxrecords) 

    The GetBaseData method, itself calls getXMLData method which retrieves pure XML data (in XDocument format) from Google.

    private static XDocument getXMLData
    	(string tableID, IEnumerable<Dimension> dimensions,
    	IEnumerable<Metric> metrics, DateTime from, DateTime to,
    	Metric sort, SortDirection direction, int maxrecords)   

    The GetBaseData method parses the XML retrieved by getXMLData method, takes out the dimension/metric pairs and passes them as a BaseData type object to our GetAnalytics method. The BaseData class's definition is as follows:

    public class BaseData
        public IEnumerable<KeyValuePair<Dimension, string>> Dimensions { get; set; }
        public IEnumerable<KeyValuePair<Metric, string>> Metrics { get; set; } 

    Now we have our data in an IEnumerable<BaseData> object. By using lambda expressions, the returned object from GetBaseData will be mapped to an IEnumerable<GAData> object and will be returned to the user:

    return data.Select(d => new GAData
        Pageviews = Convert.ToInt32(d.Metrics.FirstOrDefault
    	(met => met.Key == Metric.pageviews).Value),
        Bounces = Convert.ToInt32(d.Metrics.FirstOrDefault
    	(met => met.Key == Metric.bounces).Value),
        Entrances = Convert.ToInt32(d.Metrics.FirstOrDefault
    	(met => met.Key == Metric.entrances).Value),
        Exits = Convert.ToInt32(d.Metrics.FirstOrDefault
    	(met => met.Key == Metric.exits).Value),
        NewVisits = Convert.ToInt32(d.Metrics.FirstOrDefault
    	(met => met.Key == Metric.newVisits).Value),
        TimeOnPage = Convert.ToDouble(d.Metrics.FirstOrDefault
    	(met => met.Key == Metric.timeOnPage).Value),
        TimeOnSite = Convert.ToDouble(d.Metrics.FirstOrDefault
    	(met => met.Key == Metric.timeOnSite).Value),
        Visitors = Convert.ToInt32(d.Metrics.FirstOrDefault
    	(met => met.Key == Metric.visits).Value),
        Visits = Convert.ToInt32(d.Metrics.FirstOrDefault
    	(met => met.Key == Metric.pageviews).Value),
        UniquePageviews = Convert.ToInt32(d.Metrics.FirstOrDefault
    	(met => met.Key == Metric.uniquePageviews).Value),
        ExitPagePath = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.exitPagePath).Value,
        LandingPagePath = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.landingPagePath).Value,
        NextPagePath = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.nextPagePath).Value,
        PagePath = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.pagePath).Value,
        PageTitle = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.pageTitle).Value,
        PreviousPagePath = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.previousPagePath).Value,
        SecondPagePath = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.secondPagePath).Value,
        Browser = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.browser).Value,
        BrowserVersion = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.browserVersion).Value,
        City = d.Dimensions.FirstOrDefault
    	(dim => dim.Key ==,
        ConnectionSpeed = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.connectionSpeed).Value,
        Country = d.Dimensions.FirstOrDefault
    	(dim => dim.Key ==,
        Date = d.Dimensions.FirstOrDefault
    	(dim => dim.Key ==,
        DaysSinceLastVisit = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.daysSinceLastVisit).Value,
        Day = d.Dimensions.FirstOrDefault
    	(dim => dim.Key ==,
        FlashVersion = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.flashVersion).Value,
        Hostname = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.hostname).Value,
        IsMobile = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.isMobile).Value,
        Hour = d.Dimensions.FirstOrDefault(dim => dim.Key == Dimension.hour).Value,
        JavaEnabled = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.javaEnabled).Value,
        Language = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.language).Value,
        Latitude = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.latitude).Value,
        Longitude = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.longitude).Value,
        Month = d.Dimensions.FirstOrDefault(dim => dim.Key == Dimension.month).Value,
        NetworkDomain = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.networkDomain).Value,
        NetworkLocation = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.networkLocation).Value,
        OperatingSystem = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.operatingSystem).Value,
        OperatingSystemVersion = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.operatingSystemVersion).Value,
        PageDepth = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.pageDepth).Value,
        Region = d.Dimensions.FirstOrDefault(dim => dim.Key == Dimension.region).Value,
        ScreenColors = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.screenColors).Value,
        ScreenResolution = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.screenResolution).Value,
        SubContinent = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.subContinent).Value,
        UserDefinedValue = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.userDefinedValue).Value,
        VisitCount = Convert.ToInt32(d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.visitCount).Value),
        VisitLength = Convert.ToInt32(d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.visitLength).Value),
        VisitorType = d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.visitorType).Value,
        Week = Convert.ToInt32(d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.week).Value),
        Year = Convert.ToInt32(d.Dimensions.FirstOrDefault
    	(dim => dim.Key == Dimension.year).Value),
        Source = d.Dimensions.FirstOrDefault(dim => dim.Key == Dimension.source).Value


Points of Interest

Using Google Analytics Data API is fun and I'd recommend you to surf the code more thoroughly and see what's going on under the hood. If you have any questions, post your questions here and I'd be glad to help.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Chief Technology Officer Banicomm
Iran (Islamic Republic of) Iran (Islamic Republic of)
Microsoft Visual Studio .NET Application Programmer, Web Developer. I'm also part of YetAnotherForum's (YAF) Development Team.

You may also be interested in...


Comments and Discussions

QuestionGoogle Analytics Pin
manish_sanandiya2-Mar-15 0:21
membermanish_sanandiya2-Mar-15 0:21 
GeneralArticle needs to be updated Pin
Abhishek Pant13-Oct-14 21:54
professionalAbhishek Pant13-Oct-14 21:54 
Question(400) Bad Request (403) forbidden eror Pin
Member 99988893-Aug-14 21:03
memberMember 99988893-Aug-14 21:03 
GeneralMy vote of 3 Pin
mahmoud wafy21-May-14 11:24
membermahmoud wafy21-May-14 11:24 
QuestionError getting on production environment Pin
Member 963102718-Mar-14 21:23
memberMember 963102718-Mar-14 21:23 
AnswerRe: Error getting on production environment Pin
rachitkapoor1-Apr-14 21:19
memberrachitkapoor1-Apr-14 21:19 
QuestionError Pin
teenhappy11-Nov-13 9:20
memberteenhappy11-Nov-13 9:20 
AnswerRe: Error Pin
Member 184536615-Jan-14 7:07
memberMember 184536615-Jan-14 7:07 
GeneralRe: Error Pin
Member 963102712-Mar-14 1:40
memberMember 963102712-Mar-14 1:40 
QuestionIts giving Error 404. Pin
sameer_s5-Sep-13 20:39
membersameer_s5-Sep-13 20:39 
AnswerRe: Its giving Error 404. Pin
MrSadin1-Nov-13 0:09
professionalMrSadin1-Nov-13 0:09 
GeneralRe: Its giving Error 404. Pin
Shreya Nag27-Dec-13 0:39
memberShreya Nag27-Dec-13 0:39 
QuestionUnable to acces the data from Google Analytics..Error in 'GetProfilesData' method. Pin
Member 781298911-Apr-13 21:34
memberMember 781298911-Apr-13 21:34 
QuestionError 404 Pin
winrunner12-Feb-13 21:56
memberwinrunner12-Feb-13 21:56 
GeneralVery Nice Pin
H_SS5-Feb-13 8:03
memberH_SS5-Feb-13 8:03 
GeneralVery Nice Pin
H_SS5-Feb-13 8:01
memberH_SS5-Feb-13 8:01 
QuestionRecieved Error 404 Pin
Harshanumaan29-Jan-13 5:54
memberHarshanumaan29-Jan-13 5:54 
Hi , i'm receiving an error stating "The remote server returned an error:(404)NOT FOUND " i 've changed the api to Google Anlytics API version v3,now please tell me why i'm recieving such error.
please help me to get rid off such a situation thanks
QuestionI'm getting Object reference not set to an instance of an object error. Pin
Harpreet_12523-Jan-13 23:28
memberHarpreet_12523-Jan-13 23:28 
QuestionI'm getting Object reference not set to an instance of an object. Pin
chinnu1111-Dec-12 21:06
memberchinnu1111-Dec-12 21:06 
GeneralMy vote of 5 Pin
Dg!Mortal25-Nov-12 21:52
memberDg!Mortal25-Nov-12 21:52 
QuestionAuthenticationUrl = ""; Pin
Member 947935023-Nov-12 1:16
memberMember 947935023-Nov-12 1:16 
AnswerRe: AuthenticationUrl = ""; Pin
Akis Kontakis26-Nov-12 6:45
memberAkis Kontakis26-Nov-12 6:45 
GeneralRe: AuthenticationUrl = ""; Pin
Member 947935027-Nov-12 20:42
memberMember 947935027-Nov-12 20:42 
Questionabout average time format Pin
dipangi15-Jun-12 22:10
memberdipangi15-Jun-12 22:10 
Questionhow to specify and use Advanced Segments of Google Analytics Pin
Member 87274492-Apr-12 3:08
memberMember 87274492-Apr-12 3:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.171207.1 | Last Updated 5 Nov 2010
Article Copyright 2010 by Kamyar
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid