function getGAauthenticationToken(email, password) {

//Fetches GA authentication token, which can then be used to fetch data with the getGAdata function

//Created by Mikael Thuneberg

    try {

        if (typeof email == "undefined") {

            return "Email address missing";

        }

        if (typeof password == "undefined") {

            return "Password missing";

        }

        if (email.length == 0) {

            return "Email address missing";

        }

        if (password.length == 0) {

            return "Password missing";

        }

        password = encodeURIComponent(password);

        var responseStr

        var response = UrlFetchApp.fetch("https://www.google.com/accounts/ClientLogin", {

            method: "post",

            payload: "accountType=GOOGLE&Email=" + email + "&Passwd=" + password + "&service=analytics&Source=Mikael Thuneberg-GA Google Docs functions-1.0"

        });

        responseStr = response.getContentText();

        responseStr = responseStr.slice(responseStr.search("Auth=") + 5, responseStr.length);

        return responseStr;

    } catch (e) {

        if (e.message.indexOf("CaptchaRequired") != -1) {

            return "Complete CAPTCHA at http://www.google.com/accounts/" + e.message.slice(e.message.indexOf("CaptchaUrl=") + 11, e.message.length);

        } else {

            return "Authentication failed (" + e.message + ")";

        }

    }

}

function getGAaccountData(authToken, dataType, includeHeaders, maxRows, startFromRow) {

//Fetches account data for the authenticated user

//Input authentication token produced by the getGAauthenticationToken function

//If dataType parameter is omitted, the functions fetches a list profiles to which the user has access

//By specifying the dataType parameters as "goals", the functions will fetch a list of goals by profile

//By specifying the dataType parameters as "segments", the functions will fetch a list of advanced segments

//Created by Mikael Thuneberg

  if (typeof authToken == "undefined") {

        return "Authentication token missing";

    }

    dataType = (typeof dataType == "undefined") ? "profiles" : dataType;

    maxRows = (typeof maxRows == "undefined") ? 200 : maxRows;

    maxRows = (typeof maxRows == "string") ? 200 : maxRows;

    startFromRow = (typeof startFromRow == "undefined") ? 1 : startFromRow;

    startFromRow = (typeof startFromRow == "string") ? 1 : startFromRow;

    if (authToken.length == 0) {

        return "Authentication token missing";

    }

    if (dataType.length == 0) {

        dataType = "profiles";

    }

    if (authToken.indexOf("Authentication failed") != -1) {

        return "Authentication failed";

    }

    try {

        authToken = authToken.replace(/\n/g, "");

        dataType = dataType.toLowerCase();

        var URL = "https://www.google.com/analytics/feeds/accounts/default?max-results=" + maxRows + "&start-index=" + startFromRow

        var responseStr;

    try {    

     var response = UrlFetchApp.fetch(URL, {

            method: "get",

            headers: {

                "Authorization": "GoogleLogin auth=" + authToken,

                "GData-Version": "2"

            }

        });

    } catch (e) {

     try { 

randnumber = Math.random()*5000;

Utilities.sleep(randnumber);    

      var response = UrlFetchApp.fetch(URL, {

            method: "get",

            headers: {

                "Authorization": "GoogleLogin auth=" + authToken,

                "GData-Version": "2"

            }

        });

    } catch (e) {

       try {

        Utilities.sleep(5000);    

   var response = UrlFetchApp.fetch(URL, {

            method: "get",

            headers: {

                "Authorization": "GoogleLogin auth=" + authToken,

                "GData-Version": "2"

            }

        });

    } catch (e) {

       return "Failed to fetch data from Google Analytics (" + e.message + ")";

    }

    }

    }

        responseStr = response.getContentText();

        var XMLdoc = Xml.parse(responseStr);

        var lapset2;

        var TempArray = [];

        var RowArray = [];

        var HeaderArray = [];

        if (includeHeaders == true) {

            var rivi = 1;

            if (dataType == "segments") {

                HeaderArray[0] = "Segment ID";

                HeaderArray[1] = "Segment Name";

                HeaderArray[2] = "Segment Definition";

            } else {

                HeaderArray[0] = "Account Name";

                HeaderArray[1] = "Profile Title";

                HeaderArray[2] = "Profile Number";

            }

            TempArray[0] = HeaderArray;

        } else {

            var rivi = 0;

        }

        var sar = 0;

        var lapset;

        var dataFound = false;

        if (dataType == "segments") {

            lapset = XMLdoc.getElement().getElements();

            for (i = 0; i < lapset.length; i++) {

                if (lapset[i].getName().getLocalName() == "segment") {

                    sar = 0;

                    RowArray[0] = lapset[i].getAttribute("id").getValue();

                    RowArray[1] = lapset[i].getAttribute("name").getValue();

                    lapset2 = lapset[i].getElements();

                    for (j = 0; j < lapset2.length; j++) {

                        if (lapset2[j].getName().getLocalName() == "definition") {

                            RowArray[2] = lapset2[j].getText();

                        }

                    }

                    TempArray[rivi] = RowArray;

                    RowArray = [];

                    dataFound = true;

                    rivi++;

                    if (rivi == maxRows) {

                        return TempArray;

                    }

                } else {

                    if (lapset[i].getName().getLocalName() == "entry") {

                        break;

                    }

                }

            }

        } else { // datatype = profiles 

            lapset = XMLdoc.getElement().getElements("entry");

            for (i = 0; i < lapset.length; i++) {

                sar = 0;

                lapset2 = lapset[i].getElements();

                for (j = 0; j < lapset2.length; j++) {

                    if (lapset2[j].getName().getLocalName() == "title") {

                        RowArray[1] = " " + lapset2[j].getText();

                        dataFound = true;

                    } else {

                        if (lapset2[j].getName().getLocalName() == "property") {

                            if (lapset2[j].getAttribute("name").getValue() == "ga:accountName") {

                                RowArray[0] = lapset2[j].getAttribute("value").getValue();

                            }

                            if (lapset2[j].getAttribute("name").getValue() == "ga:profileId") {

                                RowArray[2] = lapset2[j].getAttribute("value").getValue();

                                break;

                            }

                        }

                    }

                }

                TempArray[rivi] = RowArray;

                RowArray = [];

                dataFound = true;

                rivi++;

                if (rivi == maxRows) {

                    return TempArray;

                }

            }

        }

        if (dataFound == false) {

            return "No data found";

        }

        return TempArray;

    } catch (e) {

        return "Fetching account data failed (" + e.message + ")";

    }

}

function getGAdata(authToken, profileNumber, metrics, startDate, endDate, filters, dimensions, segment, sort, includeHeaders, maxRows, startFromRow) {

//Fetches data from the GA profile specified, using the authentication token generated by the getGAauthenticationToken function

//For instructions on the parameters, see http://bit.ly/bUYMDs

//Created by Mikael Thuneberg

  try {

        startDate.getYear();

    } catch (e) {

        return "Invalid start date";

    }

    try {

        endDate.getYear();

    } catch (e) {

        return "Invalid end date";

    }

    try {

        if (typeof authToken == "undefined") {

            return "Authentication token missing";

        }

        if (typeof profileNumber == "undefined") {

            return "Profile number missing";

        }

        if (typeof metrics == "undefined") {

            return "Specify at least one metric";

        }

        if (profileNumber != parseInt(profileNumber)) {

            return "Invalid profile number";

        }

        filters = (typeof filters == "undefined") ? "" : filters;

        dimensions = (typeof dimensions == "undefined") ? "" : dimensions;

        segment = (typeof segment == "undefined") ? "" : segment;

        maxRows = (typeof maxRows == "undefined") ? 100 : maxRows;

        maxRows = (typeof maxRows == "string") ? 100 : maxRows;

        startFromRow = (typeof startFromRow == "undefined") ? 1 : startFromRow;

        startFromRow = (typeof startFromRow == "string") ? 1 : startFromRow;

        if (authToken.length == 0) {

            return "Authentication token missing";

        }

        if (profileNumber.length == 0) {

            return "Profile number missing";

        }

        if (metrics.length == 0) {

            return "Specify at least one metric";

        }

        if (authToken.indexOf("Authentication failed") != -1) {

            return "Authentication failed";

        }

        authToken = authToken.replace(/\n/g, "");

        var startDateString

        var endDateString

        var dMonth

        var dDay

        dMonth = Right(("0" + (startDate.getMonth()+1)).toString(),2);

        dDay = Right(("0" + (startDate.getDate())).toString(),2);

        startDateString = startDate.getYear() + "-" + dMonth + "-" + dDay;

        dMonth = Right(("0" + (endDate.getMonth()+1)).toString(),2);

        dDay = Right(("0" + (endDate.getDate())).toString(),2);

        endDateString = endDate.getYear() + "-" + dMonth + "-" + dDay

        if (startDateString > endDateString) {

            return "Start date should be before end date";

        }

        var URL = "https://www.google.com/analytics/feeds/data?ids=ga:" + profileNumber + "&start-date=" + startDateString + "&end-date=" + endDateString + "&max-results=" + maxRows + "&start-index=" + startFromRow;

        if (metrics.slice(0, 3) != "ga:") {

            metrics = "ga:" + metrics;

        }

        metrics = metrics.replace(/&/g, "&ga:");

        metrics = metrics.replace(/ga:ga:/g, "ga:");

        metrics = metrics.replace(/&/g, "%2C");

        URL = URL + "&metrics=" + metrics

        if (dimensions.length > 0) {

            if (dimensions.slice(0, 3) != "ga:") {

                dimensions = "ga:" + dimensions;

            }

            dimensions = dimensions.replace(/&/g, "&ga:");

            dimensions = dimensions.replace(/ga:ga:/g, "ga:");

            dimensions = dimensions.replace(/&/g, "%2C");

            URL = URL + "&dimensions=" + dimensions;

        }

        if (filters.length > 0) {

            if (filters.slice(0, 3) != "ga:") {

                filters = "ga:" + filters;

            }

            filters = filters.replace(/,/g, ",ga:");

            filters = filters.replace(/;/g, ";ga:");

            filters = filters.replace(/ga:ga:/g, "ga:");

            filters = encodeURIComponent(filters);

            URL = URL + "&filters=" + filters;

        }

        if (typeof(segment) == "number") {

            segment = "gaid::" + segment;

        }

        if (segment.length > 0) {

            if (segment.indexOf("gaid::") == -1 && segment.indexOf("dynamic::") == -1) {

                if (segment.slice(0, 3) != "ga:") {

                    segment = "ga:" + segment;

                }

                segment = "dynamic::" + segment;

            }

            segment = encodeURIComponent(segment);

            URL = URL + "&segment=" + segment;

        }

        if (sort == true) {

            URL = URL + "&sort=-" + metrics;

        }

    }

    catch (e) {

        return "Fetching data failed (" + e.message + ")";

    }

randnumber = Math.random()*5000;

Utilities.sleep(randnumber); 

    try {    

         var response = UrlFetchApp.fetch(URL, {

            method: "get",

            headers: {

                "Authorization": "GoogleLogin auth=" + authToken,

                "GData-Version": "2"

            }

        });

    } catch (e) {

     try { 

randnumber = Math.random()*5000;

Utilities.sleep(randnumber);    

         var response = UrlFetchApp.fetch(URL, {

            method: "get",

            headers: {

                "Authorization": "GoogleLogin auth=" + authToken,

                "GData-Version": "2"

            }

        });

    } catch (e) {

       try {

        Utilities.sleep(5000);    

          var response = UrlFetchApp.fetch(URL, {

            method: "get",

            headers: {

                "Authorization": "GoogleLogin auth=" + authToken,

                "GData-Version": "2"

            }

        });

    } catch (e) {

       return "Failed to fetch data from Google Analytics (" + e.message + ")";

    }

    }

    }

    try {

        var responseStr = response.getContentText();

        var XMLdoc = Xml.parse(responseStr);

        var lapset = XMLdoc.getElement().getElements("entry");

        var lapset2;

        var TempArray = [];

        var RowArray = [];

        var HeaderArray = [];

        if (includeHeaders == true) {

            var rivi = 1;

        } else {

            var rivi = 0;

        }

        var sar = 0;

        var dataFound = false;

        for (i = 0; i < lapset.length; i++) {

            sar = 0;

            lapset2 = lapset[i].getElements();

            for (j = 0; j < lapset2.length; j++) {

                if (lapset2[j].getName().getLocalName() == "dimension") {

                    RowArray[sar] = lapset2[j].getAttribute("value").getValue();

                    if (rivi == 1) {

                        HeaderArray[sar] = lapset2[j].getAttribute("name").getValue();

                    }

                    sar++;

                }

                if (lapset2[j].getName().getLocalName() == "metric") {

                    RowArray[sar] = Number(lapset2[j].getAttribute("value").getValue());

                    if (rivi == 1) {

                        HeaderArray[sar] = lapset2[j].getAttribute("name").getValue();

                    }

                    sar++;

                }

            }

            TempArray[rivi] = RowArray;

            RowArray = [];

            dataFound = true;

            rivi++;

        }

        if (dataFound == false) {

            return "No data found";

        }

        if (includeHeaders == true) {

            TempArray[0] = HeaderArray;

        }

        return TempArray;

    } catch (e) {

        return "Fetching data failed (" + e.message + ")";

    }

}

function Left(str, n){

if (n <= 0)

   return "";

else if (n > String(str).length)

   return str;

else

   return String(str).substring(0,n);

}

function Right(str, n){

    if (n <= 0)

       return "";

    else if (n > String(str).length)

       return str;

    else {

       var iLen = String(str).length;

       return String(str).substring(iLen, iLen - n);

    }

}