Generate Google Analytics E-Commerce code from C#

Tracking visitors on your e-commerce website is crucial step on internet business today, one tool from Google, call “Google Analytics” has come to help, armed with ability to track visitors from difference source traffic, content navigation, visitor’s system statistic, and most of all e-commerce tracking. Analytics E-commerce are executed by a block of JavaScript into the html code rendered to the client browser, this can sometime be difficult if you have more than one product (Which also happen on my site). Therefore we need a more powerful way generate this tracking code for Analytics, using the power of C# in ASP.NET, I’m able to create a namespace to dynamically generate the inject code for you simply at runtime.

UPDATE: July 16, 2010: Google Analytics Asynchronous Syntax

From the beginning this code was updated back to years ago and now that i’m updating the code to meet up with Google Analytics recommendation on using asynchronous syntax for informing Google about the tracking information. Also i made the code more easy to implement the code into existing.

Continue on to make the library containing the most features it could have in google analytics. i also add the Event, Campaign, Visitor Segment, and Browser settings detection to the namespace.

Ok, lets us at the namespace Google to see what we got here. We have total of 4 classes with Analytics as the master class and Transaction & Item are slaves classes. while event is independence.

1. Analytics: This class contain all the properties that google requires and it’s for generating the google javascript code into the head tag of your webpage.

2. Event: Assign visitors/customers to a particular page to a segment. normally to track return buyers.

3. Transaction: This class is for creating the transaction request for google and holding the items collection.

4. Item: This class is for storing information about each product that is included with the current transaction.

UPDATE: 5 August 2010: Attach project files

Due to some visitor are having problems viewing my codes with their browser, which my codes unreadable. So i’m making the package that visitors can download the whole project to make a better understanding with the codes that i have introduce here.

Download Google Analytics Version 1.1

Now let us see the update code shall we;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;

/// <summary>
/// Summary description for Google Analytics
/// Version:    2.0
/// Author:     Sarin Na Wangkanai
/// Website:    www.sarin.mobi
/// License:    GPL
/// </summary>
namespace Google
{
    public class Analytics
    {
        public string UA { get; set; }

        #region BrowserSettings
        public bool ClientInfo { get; set; }
        public string DomainName { get; set; }
        public bool AllowLinker { get; set; }
        public bool AllowHash { get; set; }
        public bool DetectFlash { get; set; }
        public bool DetectTitle { get; set; }
        #endregion
        #region Campaign
        public int CampaignCookieTimeout { get; set; }
        public bool CampaignTrack { get; set; }
        public string CampaignName { get; set; }
        public string CampaignMedium { get; set; }
        public string CampaignSource { get; set; }
        public string CampaignTerm { get; set; }
        public string CampaignContent { get; set; }
        public string CampaignNoOverride { get; set; }
        #endregion

        /// <summary>
        /// Google Analytics allows you to define custom segments and analyze the behavior of each segment.
        /// </summary>
        /// <remarks>http://www.google.com/support/googleanalytics/bin/answer.py?answer=57045</remarks>
        public string VisitorSegment { get; set; }

        private string GoogleJavascriptLibrary
        {
            get
            {
                StringBuilder builder = new StringBuilder();
                builder.AppendLine("(function() {");
                builder.AppendLine("\tvar ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;");
                builder.AppendLine("\tga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';");
                builder.AppendLine("\tvar s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);");
                builder.AppendLine("})();");
                return builder.ToString();
            }
        }
        private Transaction trans { get; set; }

        /// <summary>
        /// Create the google analytics tracking code instance
        /// </summary>
        /// <param name="ua">(UA-XXXXX-YY) Your web property ID, informally referred to as UA number, can be found by clicking the "check status" link or by searching for "UA-" in the source code of your web page.</param>
        public Analytics(string ua)
        {
            this.UA = ua;
            this.ClientInfo = true;
            this.AllowHash = true;
            this.DetectFlash = true;
            this.DetectTitle = true;
            this.CampaignTrack = true;
        }

        /// <summary>
        /// Add transaction tracking to the google analytics tracker code
        /// </summary>
        /// <param name="transaction">transaction object</param>
        public void AddTrans(Transaction transaction)
        {
            this.trans = transaction;
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.AppendLine("<script type=\"text/javascript\">");
            builder.AppendLine("\tvar _gaq = _gaq || [];");
            builder.AppendLine(string.Format("\t_gaq.push(['_setAccount', '{0}']);", UA));
            if (!ClientInfo) builder.AppendLine("\t_gaq.push(['_setClientInfo', false]);");
            if (DomainName != null) builder.AppendLine(string.Format("\t_gaq.push(['_setDomainName', '{0}']);", DomainName));
            if (AllowLinker) builder.AppendLine("\t_gaq.push(['_setAllowLinker', true]);");
            if (!AllowHash) builder.AppendLine("\t_gaq.push(['_setAllowHash', false]);");
            if (!DetectFlash) builder.AppendLine("\t_gaq.push(['_setDetectFlash', false]);");
            if (!DetectTitle) builder.AppendLine("\t_gaq.push(['_setDetectTitle', false]);");

            if (!CampaignTrack) builder.AppendLine("\t_gaq.push(['_setCampaignTrack', false]);");
            if (CampaignCookieTimeout > 0) builder.AppendLine(string.Format("\t_gaq.push(['_setCampaignCookieTimeout', {0}]);", CampaignCookieTimeout));
            if (CampaignName != null) builder.AppendLine(string.Format("\t_gaq.push(['_setCampNameKey', '{0}']);", CampaignName));
            if (CampaignMedium != null) builder.AppendLine(string.Format("\t_gaq.push(['_setCampMediumKey', '{0}']);",CampaignMedium));
            if (CampaignSource != null) builder.AppendLine(string.Format("\t_gaq.push(['_setCampSourceKey', '{0}']);", CampaignSource));
            if (CampaignTerm != null) builder.AppendLine(string.Format("\t_gaq.push(['_setCampTermKey', '{0}']);", CampaignTerm));
            if (CampaignContent != null) builder.AppendLine(string.Format("\t_gaq.push(['_setCampContentKey', '{0}']);", CampaignContent));
            if (CampaignNoOverride != null) builder.AppendLine(string.Format("\t_gaq.push(['_setCampNOKey', '{0}']);", CampaignNoOverride));

            if (VisitorSegment != null) builder.AppendLine(string.Format("\t_gaq.push(['_setVar','{0}']);", VisitorSegment));

            builder.AppendLine("\t_gaq.push(['_trackPageview']);");
            if (trans != null)
            {
                builder.AppendLine("\t" + trans.AddTrans());
                foreach (Item item in trans.Items)
                    builder.AppendLine("\t" + item.ToScript(trans.OrderID));
                builder.AppendLine("\t" + trans.Submit());
            }
            builder.AppendLine();
            builder.AppendLine(GoogleJavascriptLibrary);
            builder.AppendLine("</script>");
            return builder.ToString();
        }
    }
    public class Event
    {
        public string Category { get; set; }
        public string Action { get; set; }
        public string Label { get; set; }
        public string Value { get; set; }

        public Event(string category, string action)
        {
            this.Category = category;
            this.Action = action;
        }

        public Event(string category, string action, string label, string value):this(category, action)
        {
            this.Label = label;
            this.Value = value;
        }

        public override string ToString()
        {
            return string.Format("_gaq.push(['_trackEvent', '{0}', '{1}', '{2}', '{3}]);",
                Category, Action, Label, Value);
        }
    }
    public class Transaction
    {
        public string OrderID { get; set; }     // order ID - required
        public string StoreName { get; set; }   // affiliation or store name
        public decimal Total { get; set; }      // total - required
        public decimal Tax { get; set; }        // tax
        public decimal Shipping { get; set; }   // shipping cost
        public string City { get; set; }        // city
        public string State { get; set; }       // state or province
        public string Country { get; set; }     // country

        public List<Item> Items { get; set; }   // List of itmes in this invoice transaction

        /// <summary>
        /// The transaction object stores all the related information about a single transaction, such as the order ID, shipping charges, and billing address.
        /// </summary>
        /// <param name="orderID">transaction order id (required)</param>
        /// <param name="storename">affiliation or store name</param>
        /// <param name="tax">tax</param>
        /// <param name="shipping">shipping cost</param>
        /// <param name="city">city</param>
        /// <param name="state">state or province</param>
        /// <param name="country">country</param>
        public Transaction(string orderID, string storename, decimal tax, decimal shipping, string city, string state, string country)
        {
            this.OrderID = orderID;
            this.StoreName = storename;
            this.Tax = tax;
            this.Shipping = shipping;
            this.City = city;
            this.State = state;
            this.Country = country;
            this.Items = new List<Item>();
        }

        /// <summary>
        /// add item might be called for every item in the shopping cart
        /// where your ecommerce engine loops through each item in the cart and
        /// prints out _addItem for each
        /// </summary>
        /// <param name="item">item object</param>
        public void Add(Item item)
        {
            this.Total += (item.Price * item.Quantity);
            this.Items.Add(item);
        }

        #region googlejavascript
        /// <summary>
        /// create a transaction javascript method call
        /// </summary>
        /// <returns>google javascript codes</returns>
        internal string AddTrans()
        {
            return string.Format("_gaq.push(['_addTrans', '{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}']);",
                OrderID, StoreName, Total, Tax, Shipping, City, State, Country);
        }
        /// <summary>
        /// submits transaction to the Analytics servers
        /// </summary>
        /// <returns>google javascript codes</returns>
        internal string Submit()
        {
            return "_gaq.push(['_trackTrans']);";
        }
        #endregion
    }
    public class Item
    {
        public string SKU { get; set; }         // SKU/code - required
        public string Name { get; set; }        // product name
        public string Category { get; set; }    // category or variation
        public decimal Price { get; set; }      // unit price - required
        public int Quantity { get; set; }       // quantity - required

        /// <summary>
        /// tracks information about each individual item in the user's shopping cart
        /// and associates the item with each transaction.
        /// </summary>
        /// <param name="sku">SKU/Code (required)</param>
        /// <param name="name">Product name (optional)</param>
        /// <param name="category">Category (optional)</param>
        /// <param name="price">unit price (required)</param>
        /// <param name="quantity">quantity (required)</param>
        public Item(string sku, string name, string category, decimal price, int quantity)
        {
            this.SKU = sku;
            this.Name = name;
            this.Category = category;
            this.Price = price;
            this.Quantity = quantity;
        }

        /// <summary>
        /// Create a item javascript method call
        /// </summary>
        /// <param name="orderid">order ID for the transcation</param>
        /// <returns>google javascript codes</returns>
        internal string ToScript(string orderid)
        {
            return string.Format("_gaq.push(['_addItem', '{0}', '{1}', '{2}', '{3}', '{4}', '{5}']);",
                orderid, SKU, Name, Category, Price, Quantity);
        }
    }
}

As you could see the code seem to more complex then older version, but believe me it’s much more easier to use in your web application. As all with OOP combine the aid of IntelliSense, a summary of the how to use the method will popup on fly when you are imputing the data to the function.

What about starting the using the code then. well for my recommendation would be to create a Google.Analytics property in the masterpage and create the instance of the object with overriding the OnInit() (if the instance is created in Page_Load() then transaction will never be populated into the object). Example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class MasterPage : System.Web.UI.MasterPage
{
    public Google.Analytics analytics { get; set; }

    protected override void OnInit(EventArgs e)
    {
        analytics = new Google.Analytics("UA-XXXXX-YY");
        base.OnInit(e);
    }
}

And then add the Google.Analytics.ToString() in the header of the html code of the master page.

<head runat="server">
    <title></title>
    <asp:ContentPlaceHolder id="head" runat="server">
    </asp:ContentPlaceHolder>
    <%= analytics.ToString() %>
</head>

Then finally we can add the transaction to the analytics class in the thankyou.aspx page when customer has completed the payment to your product/service.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Thankyou : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Google.Transaction transaction = new Google.Transaction("1234", "sathai", 0, 10, "ruangsit", "pathumtani", "thailand");
        transaction.Add(new Google.Item("PLOVE", "Product of love", "love", 19.99m, 1));
        (Master as MasterPage).analytics.AddTrans(transaction);
    }
}

what is the difference if the transaction added to the analytics object in the masterpage property. here is a figure of how the javascript code would look like if the transaction was not added to the analytics object;

And this source view when the transaction has been added to the analytics object;

I hope that you enjoy this updated and useful post of my about google analytics c# backend javascript generator namespace.


Kick It on DotNetKicks.com

  • Ray

    Damn!
    No one gives you a thumb up?
    I do!

  • http://www.sarin.mobi Sarin Na Wangkanai

    Thanks :)

  • http://www.ivesmozart.com Ives

    This is going to be very useful. Thanks for sharing this!

  • prakash singh

    Thanks for this useful information and code on GA.It helped me a lot.

  • Marco Morreale

    Great code!
    Thanks
    M

  • Marco Morreale

    Just one question:
    Is this code in addition to the script that should be added at the end of the master page, just before the tag? I think it is just for page tracking (no transactions).
    Maybe you shoul provide a property to set wether the base script is present in the master page or should be added by your class.
    I fear doubled script could cause page hits be counted twice.
    Thanks in advance
    Marco

  • http://www.sarin.mobi Sarin Na Wangkanai

    Well, first of all google analytics script tag from google is for tracking page tracking.

    And this code is for telling google that your visitor has made a purchase on your website on the payment (or invoice) complete page. so to an understanding that this code is for adding the transaction not page tracking.

    meaning you are not double doing it.

    your welcome.

  • Marco Morreale

    I think I found a little bug in the code.
    The first parameter of AddItem function should be the id of the transaction (“1234″ for instance) not the item number.
    Otherwise ga could not relate items to transacitions.
    Item number is the SKU parameter.

  • http://www.sarin.mobi Sarin Na Wangkanai

    its been 2 years since i wrote this code, i’m not sure if the method i used id still has validity.

    I will check google help and update the modified code, then get back to your on this.

  • http://www.sarin.mobi Sarin Na Wangkanai

    I have updated this code to compile with Google Analytics recommendation on asynchronous syntax. Also i have extended more features into the code to cover more aspect of google analytics website tracking system.

    Please post be me back if their is any bugs related to this new update.

  • http://www.sarin.mobi Sarin Na Wangkanai

    I went back to fix all code syntax that was showing incorrectly, in order to make this post most accurate as possible.

    I hope you enjoy this update :)

  • Tomas

    It would be cool that Transaction code would be executed even if asp.net web page is not loaded in browser. Now your code only works if JavaScript is execute din browser, but it do not work if web page is executed from web service like PayPal Instant Payment Notification.
    If you will look at http://www.diaryofaninja.com/projects/details/ga-dot-net#api
    you will find solution which works even if GA code is not loaded in browser.

    Please add such feature to your code.

  • Pepin

    Hello there, I am trying add the code in asp.net 2.0 and C# but i am getting an error in the file google.cs at this line

    public string UA { get; set; }

    and the error is
    ‘Google.Analytics.UA.get’ must declare a body because it is not marked abstract or external

    can you please help me out.
    Thanks and appreciate it

  • http://www.sarin.mobi Sarin Na Wangkanai

    I think that you are missing the whole point of tracking with google analytics, because if your customer execute the transaction on their browser you would get tracking details of who their are. but if you did that in the back-end, you wouldn’t have that information or that it will only show that paypal is your customer. which would make no use in analyzing your customer behavioral on your online store.

    if your customer have made an order on your website and that invoice have then void (unpaid & expired). you could always remove the transaction that from google analytics and that show you have a negative transaction.

    if this feature of removing transaction from google analytics is what everybody is interest, then i might considering adding it to the codes.

  • http://www.sarin.mobi Sarin Na Wangkanai

    That should not happen in. have you created an instance of the google tracking code in your masterpage OnInit() method like this “analytics = new Google.Analytics(“UA-XXXXX-YY”);” yet?

  • Pepin

    Yes sir, i have.. here is my code in the masterpage code behind page

    // adding google analytics reference
    public Google.Analytics analytics {get; set;}

    protected override void OnInit(EventArgs e)
    {
    analytics = new Google.Analytics(“UA-XXXXXXX-X”);

    base.OnInit(e);
    }

    I have placed this code in my parent masterpage. then i have added this reference to the masterpage file

    NOW IN MY THANKYOU PAGE code behind ( which is based on the parent masterpage)

    Google.Transaction transaction = new Google.Transaction(lOrderId.Text, lBillingName.Text, 0, lShipping.Text, ” “, ” “, “”);
    transaction.Add(new Google.Item(lOrderId.Text,” “,” “,” “,” “));
    ((styles_StandardLayout)this.Master).analytics.AddTrans(transaction);

    I would appreciate it if you can guide me sir.

    Thanks
    Pepin

  • http://www.sarin.mobi Sarin Na Wangkanai

    i did some research on your topic. the reason this is happening is because asp.net c# 2.0 does not have Automatic Properties.
    meaning you can’t do => public Google.Analytics analytics {get; set;}
    you would need to create a private variable for all your property to link to.
    read up more on this at http://footheory.com/blogs/bennie/archive/2007/08/02/new-features-in-c-3-0-part-3-automatic-properties-object-initializers-and-collection-initializers.aspx

  • http://new.cartridgesdirect.com.au Shailendra Jain

    I did not have any master page i want to include this code into my user control(.ascx).
    I have include
    code into a user control (.ascx)
    So what i will take insted of
    (Master as MasterPage).analytics.AddTrans(transaction);
    into another user control.

  • http://www.sarin.mobi Sarin Na Wangkanai

    Yes, you could do that. but i’m not able to answer that question out of the blue right now, using 36k internet in the middle of no where. could you research with google and update the solution for everyone here please.
    thanks

  • Simon

    Very useful thanks. Be careful if you have apostrophes in your product names. We thought it was all working but realized Google was only tracking some of our sales. Obviously you must escape any apostrophes before using this code.

  • cha

    Hi,
    Great Job! but i wonder how do you implement Paypal’s IPN and PDT integration with google analytics tracking. Hope you can help me on this since im kinda new with GA.

    Thanks a lot!

  • http://www.facebook.com/people/Ronald-Shawn/100001960464404 Ronald Shawn

    Hey Sarin,
    Its wonderful to have this much level of OOP.
    I appreciate your efforts and thanking you for your sharing.
    The way you have organized/presented it is completely an awesome thing, just wow.

    Now, There are couple of confusion with it cause I may be less informed about it.
    1st – Why you have choose to go for asynchronous tracking over traditional tracking, is there any advantage of it over the later one?

    2nd – While I have already use Google analytics for Page Tracking for SEO, so Do I have to write this code for GA once again on master page for this E-Comm tracking?

    3rd – In this code you haven’t included Total(total amount of the order), so does it work properly without carrying total amount with it?

    Thanks once again, this have had helped me a lot.
    I hope you are still active and checking the responses you get on regular basis.
    All the best.

  • http://www.sarin.mobi/ sathai

    your welcome, and to help clear things up for you.

    1. you could order the asynchronous method to process in the background of the world wide web and when it is complete your application be inform that the event completed has risen. This type of usage make most sense in AJAX style web application, where your entire web site is one page (or more) is process on a single web page. but look like to so many page has been loaded.

    2. the class that i have written has already called google analytics tracking. therefore, you don’t have to call it again. once is okie for google.

    3. total was not in the google manual when i written this tracker class. but i don’t have any problem in google analytics report page, this is because sums up the total with each transaction for you already.

    again your welcome. i check daily if anybody comments on my blog. don’t have much time to write more new quality post lately.

  • Dave

    Hi Sarin, great piece of code, thanks!

    Just one question, how do I add events to the analytics as it isn’t documented?

    Many thanks,

    Dave

  • http://www.sarin.mobi/ sathai

    your welcome, here is a 15secs search from google about analytics events mate;

    http://code.google.com/apis/analytics/docs/tracking/eventTrackerOverview.html

    good luck tracking there :)

  • Isfrench

    Hi, 

     the child page is not recognizing the analtyics properties from its masterpage. i am getting an error at the following line [on the analytics keyword]

    (Masteras MasterPage).analytics.AddTrans(transaction);as MasterPage).analytics.AddTrans(transaction);
    Any idea?

  • Andrew__clements

    Did you manage to resolve this issue?

  • Andrew__clements

    Re  IsFrench – I was using  clause, this I just need to use Master.analyics

  • bjarkeck

    Just what i needed, thank you!

  • sandeep

    (Master as CallYourMasterpage name).analytics.AddTrans(transaction);